I have a number of buttons that switch the application page. The buttons have 2 states, pressed and not, for each state the Menu style is implemented - normal and MenuIn - pressed (that is, the user has this page open now). In styles, only the color changes.

Now I have each button attached to a handler, which with the help of a switch , by the name of the button performs the necessary actions, namely, opens the desired page, sets all MenuIn buttons to the Menu style and sets the MenuIn button of the current section. As a result, I get a huge footcloth of duplicate rows.

How to competently shorten the code, maybe in the style of how to determine whether the button is pressed or not, maybe something else?


 private void ButtonEvent(string name) { switch (name) { case "ChangeBg": BackgroundEvent.Restart(); break; case "HomeBtn": HomeBtn.Style = (Style) Application.Current.Resources["MenuIn"]; NewsBtn.Style = (Style) Application.Current.Resources["Menu"]; AlertsBtn.Style = (Style) Application.Current.Resources["Menu"]; InvasionsBtn.Style = (Style) Application.Current.Resources["Menu"]; SettingsBtn.Style = (Style) Application.Current.Resources["Menu"]; InfoBtn.Style = (Style) Application.Current.Resources["Menu"]; TradeBtn.Style = (Style) Application.Current.Resources["Menu"]; ActMissionsBtn.Style = (Style) Application.Current.Resources["Menu"]; MainFrame.Navigate(new Uri("View/HomePage.xaml", UriKind.Relative)); break; case "NewsBtn": HomeBtn.Style = (Style) Application.Current.Resources["Menu"]; NewsBtn.Style = (Style) Application.Current.Resources["MenuIn"]; AlertsBtn.Style = (Style) Application.Current.Resources["Menu"]; InvasionsBtn.Style = (Style) Application.Current.Resources["Menu"]; SettingsBtn.Style = (Style) Application.Current.Resources["Menu"]; InfoBtn.Style = (Style) Application.Current.Resources["Menu"]; TradeBtn.Style = (Style) Application.Current.Resources["Menu"]; ActMissionsBtn.Style = (Style) Application.Current.Resources["Menu"]; //MyPopup.IsOpen = true; MainFrame.Navigate(new Uri("View/NewsPage.xaml", UriKind.Relative)); break; case "AlertsBtn": HomeBtn.Style = (Style) Application.Current.Resources["Menu"]; NewsBtn.Style = (Style) Application.Current.Resources["Menu"]; AlertsBtn.Style = (Style) Application.Current.Resources["MenuIn"]; InvasionsBtn.Style = (Style) Application.Current.Resources["Menu"]; SettingsBtn.Style = (Style) Application.Current.Resources["Menu"]; InfoBtn.Style = (Style) Application.Current.Resources["Menu"]; TradeBtn.Style = (Style) Application.Current.Resources["Menu"]; ActMissionsBtn.Style = (Style) Application.Current.Resources["Menu"]; //MyPopup.IsOpen = false; //BodyFrame.Navigate(new Uri("Pages/AlertsPage.xaml", UriKind.Relative)); break; case "TradeBtn": HomeBtn.Style = (Style) Application.Current.Resources["Menu"]; NewsBtn.Style = (Style) Application.Current.Resources["Menu"]; AlertsBtn.Style = (Style) Application.Current.Resources["Menu"]; InvasionsBtn.Style = (Style) Application.Current.Resources["Menu"]; SettingsBtn.Style = (Style) Application.Current.Resources["Menu"]; InfoBtn.Style = (Style) Application.Current.Resources["Menu"]; TradeBtn.Style = (Style) Application.Current.Resources["MenuIn"]; ActMissionsBtn.Style = (Style) Application.Current.Resources["Menu"]; //BodyFrame.Navigate(new Uri("Pages/TradePage.xaml", UriKind.Relative)); break; case "InvasionsBtn": HomeBtn.Style = (Style) Application.Current.Resources["Menu"]; NewsBtn.Style = (Style) Application.Current.Resources["Menu"]; AlertsBtn.Style = (Style) Application.Current.Resources["Menu"]; InvasionsBtn.Style = (Style) Application.Current.Resources["MenuIn"]; SettingsBtn.Style = (Style) Application.Current.Resources["Menu"]; InfoBtn.Style = (Style) Application.Current.Resources["Menu"]; TradeBtn.Style = (Style) Application.Current.Resources["Menu"]; ActMissionsBtn.Style = (Style) Application.Current.Resources["Menu"]; //BodyFrame.Navigate(new Uri("Pages/InvasionsPage.xaml", UriKind.Relative)); break; case "InfoBtn": HomeBtn.Style = (Style) Application.Current.Resources["Menu"]; NewsBtn.Style = (Style) Application.Current.Resources["Menu"]; AlertsBtn.Style = (Style) Application.Current.Resources["Menu"]; InvasionsBtn.Style = (Style) Application.Current.Resources["Menu"]; SettingsBtn.Style = (Style) Application.Current.Resources["Menu"]; InfoBtn.Style = (Style) Application.Current.Resources["MenuIn"]; TradeBtn.Style = (Style) Application.Current.Resources["Menu"]; ActMissionsBtn.Style = (Style) Application.Current.Resources["Menu"]; //BodyFrame.Navigate(new Uri("Pages/InfoPage.xaml", UriKind.Relative)); break; case "SettingsBtn": HomeBtn.Style = (Style) Application.Current.Resources["Menu"]; NewsBtn.Style = (Style) Application.Current.Resources["Menu"]; AlertsBtn.Style = (Style) Application.Current.Resources["Menu"]; InvasionsBtn.Style = (Style) Application.Current.Resources["Menu"]; InfoBtn.Style = (Style) Application.Current.Resources["Menu"]; SettingsBtn.Style = (Style) Application.Current.Resources["MenuIn"]; TradeBtn.Style = (Style) Application.Current.Resources["Menu"]; ActMissionsBtn.Style = (Style) Application.Current.Resources["Menu"]; //BodyFrame.Navigate(new Uri("Pages/SettingsPage.xaml", UriKind.Relative)); break; case "ActMissionsBtn": HomeBtn.Style = (Style) Application.Current.Resources["Menu"]; NewsBtn.Style = (Style) Application.Current.Resources["Menu"]; AlertsBtn.Style = (Style) Application.Current.Resources["Menu"]; InvasionsBtn.Style = (Style) Application.Current.Resources["Menu"]; InfoBtn.Style = (Style) Application.Current.Resources["Menu"]; SettingsBtn.Style = (Style) Application.Current.Resources["Menu"]; TradeBtn.Style = (Style) Application.Current.Resources["Menu"]; ActMissionsBtn.Style = (Style) Application.Current.Resources["MenuIn"]; //BodyFrame.Navigate(new Uri("Pages/ActiveMissionsPage.xaml", UriKind.Relative)); break; } } 

enter image description here

  • one
    HomeBtn.Style = (Style) Application.Current.Resources[name == "HomeBtn" ? "MenuIn" : "Menu"]; - PetSerAl
  • I'm not sure that I understood the question correctly, but can't such a task be solved with a regular style? - user227049
  • I think your task can be solved much easier, do you have the opportunity to add a screenshot? - user227049
  • @PetSerAl The option is pretty good, I will adopt if there is no better. - EvgeniyZ
  • @FoggyFinder So I’m asking how) I currently implemented it in two different styles, I know that Button has several types, one of which seems to be clamped / pressed, but I still don’t understand how to work with it correctly. I'll do the screen now. - EvgeniyZ

3 answers 3

It looks wrong semantically.

First, each button must be responsible for itself , a third-party code should not be needed.

Then, most likely you should not have different styles for different button states. In order to change the image, simply apply a trigger. The necessary pieces of information for the trigger put in attached property.

The result is something like that.

 <Style TargetType="ToggleButton" x:Key="MenuButton"> <Setter Property="Width" Value="24"/> <!-- или сколько там надо --> <!-- остальные свойства --> <Style.Triggers> <Trigger Property="IsChecked" Value="True"> <Setter Property="Background" Value="Pink"/> <!-- и так далее --> </Trigger> </Style.Triggers> </Style> 

The need for ButtonEvent disappears.


In order for the ToggleButton set to behave like RadioButton 's, you can take RadioButton 's and make them:

 <Grid> <Grid.Resources> <Style TargetType="ToggleButton" x:Key="MenuButton" BasedOn="{StaticResource {x:Type ToggleButton}}"> <Setter Property="Width" Value="30"/> <Setter Property="Height" Value="30"/> <!-- остальная часть стиля --> </Style> </Grid.Resources> <StackPanel Orientation="Vertical" Width="30"> <RadioButton Style="{StaticResource MenuButton}" GroupName="First"/> <RadioButton Style="{StaticResource MenuButton}" GroupName="First"/> <RadioButton Style="{StaticResource MenuButton}" GroupName="First"/> <Grid Height="10"/> <RadioButton Style="{StaticResource MenuButton}" GroupName="Second"/> <RadioButton Style="{StaticResource MenuButton}" GroupName="Second"/> <RadioButton Style="{StaticResource MenuButton}" GroupName="Second"/> </StackPanel> </Grid> 

To bind commands to each button, I would do so. First, in DataContext (e., VM) would put a collection of commands.

Instead of creating buttons manually, I would take ItemsControl :

 <ItemsControl ItemsSource="{Binding Commands}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <RadioButton Style="{StaticResource MenuButton}" GroupName="First" Command="{Binding}"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> 

By pressing the button, the command would be called, and let it decide what to do next.

If your control is actually a ToolBar , you can use the ToolBar instead of ItemsControl .

 <ToolBarTray Orientation="Vertical"> <ToolBar ItemsSource="{Binding Commands}"> <ItemsControl.ItemTemplate> <DataTemplate> <RadioButton Style="{StaticResource MenuButton}" GroupName="First" Command="{Binding}"/> </DataTemplate> </ItemsControl.ItemTemplate> </ToolBar> </ToolBarTray> 
  • I tried using this example, created a WPF project, in Window.Resources added the code you specified, created 3 ToggleButton buttons and tied them to the style. It turned out that they did not change my color to the one indicated in the trigger. Well, okay, you can figure it out. Another question - how can I remove the other buttons IsChecked when I click on one of them? After all, I do not need all the buttons to be highlighted. - EvgeniyZ
  • @EvgeniyZ: Try this trick: pastebin.com/G65jTZ54 - VladD
  • In, here it is directly similar to what you need. How now to competently force them to open the necessary page? Hang all at one event Checked or for each different? As I understand it, it is also possible for one event, where you can determine which page to open by name, but you’re not saying that you’re saying. So how to be?) - EvgeniyZ
  • one
    @EvgeniyZ, I think you needed to customize TabControl, not buttons. - Vlad
  • @EvgeniyZ: Added the answer. - VladD

You can try to shove all the buttons in the myButtons collection, then it turns out something like:

 private void ButtonEvent(string name) { if (name == "ChangeBg") { BackgroundEvent.Restart() return; } var myButtons = new[] { HomeBtn, NewsBtn, AlertsBtn, InvasionsBtn, SettingsBtn, InfoBtn, TradeBtn, ActMissionsBtn }; foreach(var element in myButtons) { if (element.Name == name) element.Style = (Style) Application.Current.Resources["MenuIn"]; else element.Style = (Style) Application.Current.Resources["Menu"]; } BodyFrame.Navigate(new Uri("Pages/" + name.Substring(0, name.Length - 3) + "Page.xaml", UriKind.Relative)); } 

UPD : As correctly noted @Andrey, it would be much better somewhere to write something like:

 readonly Style MenuInStyle = (Style) Application.Current.Resources["MenuIn"]; readonly Style MenuStyle = (Style) Application.Current.Resources["Menu"] 

Then the code becomes clearer:

 private void ButtonEvent(string name) { if (name == "ChangeBg") { BackgroundEvent.Restart() return; } var myButtons = new[] { HomeBtn, NewsBtn, AlertsBtn, InvasionsBtn, SettingsBtn, InfoBtn, TradeBtn, ActMissionsBtn }; foreach(var element in myButtons) { if (element.Name == name) element.Style = MenuInStyle; else element.Style = MenuStyle; } BodyFrame.Navigate(new Uri("Pages/" + name.Substring(0, name.Length - 3) + "Page.xaml", UriKind.Relative)); } 
  • Thanks for the answer, but to loop through the elements, is it like “not good”, or am I mistaken? - EvgeniyZ
  • @EvgeniyZ Never heard anything like it. In fact, "loop through all the elements" is no different from "process each element in the same way". - Philippe
  • OK, thanks for answer. - EvgeniyZ
  • @EvgeniyZ You're welcome! - Philippe
  • Now that the styles are saved in variables, it's time to use the ternary operator! :) - Andrew NOP
 private void ButtonEvent(string name) { HomeBtn.Style = (Style) Application.Current.Resources["Menu"]; NewsBtn.Style = (Style) Application.Current.Resources["Menu"]; AlertsBtn.Style = (Style) Application.Current.Resources["Menu"]; InvasionsBtn.Style = (Style) Application.Current.Resources["Menu"]; SettingsBtn.Style = (Style) Application.Current.Resources["Menu"]; InfoBtn.Style = (Style) Application.Current.Resources["Menu"]; TradeBtn.Style = (Style) Application.Current.Resources["Menu"]; ActMissionsBtn.Style = (Style) Application.Current.Resources["Menu"]; switch (name) { case "ChangeBg": BackgroundEvent.Restart(); break; case "HomeBtn": HomeBtn.Style = (Style) Application.Current.Resources["MenuIn"]; MainFrame.Navigate(new Uri("View/HomePage.xaml", UriKind.Relative)); break; case "NewsBtn": NewsBtn.Style = (Style) Application.Current.Resources["MenuIn"]; MainFrame.Navigate(new Uri("View/NewsPage.xaml", UriKind.Relative)); break; case "AlertsBtn": AlertsBtn.Style = (Style) Application.Current.Resources["MenuIn"]; BodyFrame.Navigate(new Uri("Pages/AlertsPage.xaml", UriKind.Relative)); break; case "TradeBtn": TradeBtn.Style = (Style) Application.Current.Resources["MenuIn"]; BodyFrame.Navigate(new Uri("Pages/TradePage.xaml", UriKind.Relative)); break; case "InvasionsBtn": InvasionsBtn.Style = (Style) Application.Current.Resources["MenuIn"]; BodyFrame.Navigate(new Uri("Pages/InvasionsPage.xaml", UriKind.Relative)); break; case "InfoBtn": InfoBtn.Style = (Style) Application.Current.Resources["MenuIn"]; BodyFrame.Navigate(new Uri("Pages/InfoPage.xaml", UriKind.Relative)); break; case "SettingsBtn": SettingsBtn.Style = (Style) Application.Current.Resources["MenuIn"]; BodyFrame.Navigate(new Uri("Pages/SettingsPage.xaml", UriKind.Relative)); break; case "ActMissionsBtn": ActMissionsBtn.Style = (Style) Application.Current.Resources["MenuIn"]; BodyFrame.Navigate(new Uri("Pages/ActiveMissionsPage.xaml", UriKind.Relative)); break; } } 

(Update) But is such an example appropriate?

 private void ButtonEvent(string name) { if (name == "ChangeBg") { BackgroundEvent.Restart(); return; } HomeBtn.Style = (Style) Application.Current.Resources[name != "HomeBtn" ? "Menu" : "MenuIn"]; NewsBtn.Style = (Style) Application.Current.Resources[name != "NewsBtn" ? "Menu" : "MenuIn"]; AlertsBtn.Style = (Style) Application.Current.Resources[name != "AlertsBtn" ? "Menu" : "MenuIn"]; InvasionsBtn.Style = (Style) Application.Current.Resources[name != "InvasionsBtn" ? "Menu" : "MenuIn"]; SettingsBtn.Style = (Style) Application.Current.Resources[name != "SettingsBtn" ? "Menu" : "MenuIn"]; InfoBtn.Style = (Style) Application.Current.Resources[name != "InfoBtn" ? "Menu" : "MenuIn"]; TradeBtn.Style = (Style) Application.Current.Resources[name != "TradeBtn" ? "Menu" : "MenuIn"]; ActMissionsBtn.Style = (Style) Application.Current.Resources[name != "ActMissionsBtn" ? "Menu" : "MenuIn"]; BodyFrame.Navigate(new Uri("Pages/" + name.Substring(0, name.Length - 3) + "Page.xaml", UriKind.Relative)); } 
  • one
    Thank you for the answer, but I think it will change the “awl on soap”, but will shorten a couple of lines, but the code itself remains a long wrapper. - EvgeniyZ
  • Thank you, the second option is better. - EvgeniyZ
  • 2
    I’m confused by the fact that you climb into (Style) Application.Current.Resources[... ? Is it really impossible to save to a variable and access it, readability will increase several times - no need to look at the indexer parameter in each line (and it’s exactly the same as in the previous line, one of the characters is no different?) @EvgeniyZ - Andrey NOP
  • Well, in order to help the compiler help you need to save the names of the resources in a constant and work with it. Here you are no longer sealed in the symbol - the code simply will not compile ... - Andrew NOP
  • @ Andrei Well, I’m asking for advice) Could you write a simple example of how and what to save and handle? - EvgeniyZ