Get button style name - c#

I have several styles on Window.Resources that I apply to several buttons with C#. Then I need to change the style but first I need to know what is the current style that is applied to the button I want to change the style.
I can't find the way to get the style name from the button!

Did you try Button.Style property? If explcit setting of style is done using resource Key then you should get the current style of the button using Button.Style propetry otherwise it is a little tricky to gather all Style related information at a control level.
And there are reasons for this. Styles are inherited and could be overriden at distinct element scopes such as App, Window, UserControl, Ancestor UIElements and finally the individual control. So when you access Button.Style property you get a style that was the last immediate style applied to the Button. If the style is BasedOn another Style then Style.BasedOn will give you the parent / base Style. Again if that BasedOn style is derived from another Style we will get that as Style.basedOn.BasedOn... etc.
I hope this makes sense. :-)

I think you are making a mistake in terms of design/architecture if you approach your issue this way. If you need to change styles conditionally you can create UI-elements based on objects which hold the relevant information using data-binding and templating.

That's a good question (+1).
This is just my thought which may not be very accurate. I doubt if it makes sense to get a style for a UI control. Suppose you apply style "style1" to an UI control and then you can set individual attributes like foreground/background.... Now, what would be the style?
If you want to maintain/track the state of the button, that should be handled either as visual states or in your code behind (ViewModel/Model) probably.

See: Style
public void FooFunc()
{
Button myButton = ...;
Console.WriteLine("The Style: {0}", myButton.Style);
}
I think that's what you're looking for?

Thanks for your answers, I'm using this function from another stackoverflow.. it works and returns the style name into a string!
static public string FindNameFromResource(ResourceDictionary dictionary, object resourceItem)
static public string FindNameFromResource(ResourceDictionary dictionary, object resourceItem)
{
foreach (object key in dictionary.Keys)
{
if (dictionary[key] == resourceItem)
{
return key.ToString();
}
}
return null;
}

#Max,
I'm new to WPF, and had to toggle my Border object's style between one of two known Styles it can have. Rather than use the linear search in FindNameFromResource, I instead instead did this ...
Style normal = (Style)this.Resources["NormalBorder"];
Style strong = (Style)this.Resources["StrongBorder"];
border.Style = border.Style == normal ? strong : normal;

Related

Attached Property and DynamicResource

I'm trying to do set a DynamicResource on a content of a Attached Property but this isn't working. Trying to understand why, but I can't figure it out.
Basically, I'm implementing a watermark on a textbox using the code available at: Watermark / hint text / placeholder TextBox in WPF
provided by John Myczek
and using it as so:
<TextBox Text="{Binding SomeProperty}">
<helper:WatermarkService.Watermark>
<TextBlock FontStyle="Italic" Text="{DynamicResource SomeResource}" />
</helper:WatermarkService.Watermark>
</TextBox>
the inner TextBlock works just fine if it is outside the WatermarkService.Watermark attached property. The SomeResource for some reason is empty.
My resources are being loaded as so this.Resources.MergedDictionaries.Add(lastDictionary); since the app is localized and the data is being retrieved from a central place.
Do the controls on the attached properties share the same resources set as their "parents"? What is wrong here?
Thank you
The problem is clear. Dynamic resources are resolved by parsing upwards the logical tree. The dynamic resource is not found because your textblock is not in the correct logical tree, probably he does not have a logical parent and that is why the resource is not found.
You could solve it by adding it to the correct logical tree like for example it could be the child of the textbox. It is not so trivial and depends also on the usage that is required, because the customization of the logical tree is not so trivial.
There is not so simple like having a public method AddLogicalChild because then you would mess up the entire system. Now the question is who has the responsibility of doing this. The general solution could be to have a custom TextBox that overrides logical children related methods and returns also the watermark textblock.
It is not the global solution but in your case you could have a custom textbox overriding the LogicalChildren property like this:
public class WaterTextBox : TextBox
{
protected override IEnumerator LogicalChildren
{
get
{
ArrayList list = new ArrayList();
list.Add(WatermarkService.GetWatermark(this));
return (IEnumerator)list.GetEnumerator();
}
}
}
Remember this is just a workaround and this way would work only on your custom textboxes with dynamic resources.
Also it is not the correct implementation because you should add the watermark to the other logical children not ignore the other logical children and have only the watermark which is not even checked for null like this:
public class WaterTextBox : TextBox
{
protected override IEnumerator LogicalChildren
{
get
{
ArrayList list = new ArrayList();
IEnumerator enumerator = base.LogicalChildren;
while (enumerator.MoveNext())
{
list.Add(enumerator.Current);
}
object watermark = WatermarkService.GetWatermark(this);
if (watermark != null && !list.Contains(watermark))
{
list.Add(WatermarkService.GetWatermark(this));
}
return (IEnumerator)list.GetEnumerator();
}
}
}
To make it more general you should define an interface like IWatermark defining a property like IsWaterMarkAdded which will be implemented by your custom TextBox and ComboBox and will be used by the watermark service. The LogicalChildren override will check for the value of this property. This way you can extend functionality for your TextBox and ComboBox but still it is not an extensible solution for any control.

how could i do this in a smarter way ? (list of images to set a status on)

I'm still in the beginning stage of learning c#, so i have a question about a part of my code.
I strongly have the feeling there should be a way smarter way to accomplish what i try to do:
So what do i have:
A WPF window, with a whole bunch of images on it.
At the start, i want them all to be set to Hidden, so at the initialize part of the window, i set them all hidden and do it like this:
.....
IMx01y01W.Visibility = Visibility.Hidden;
IMx23y73W.Visibility = Visibility.Hidden;
IMx31y21W.Visibility = Visibility.Hidden;
IMx03y16W.Visibility = Visibility.Hidden;
.....
There is a logical in the names of the images like IMx##y##W, where the ## are the variable numbers.
As stated above, i strongly have the feeling that there should really be some smarter way to do this.
=======
EDIT 1
Ok so far i ended up with this:
foreach (object obj in LogicalTreeHelper.GetChildren(this))
{
if (obj is Image)
{
Image obj = (Image)item;
obj.Visibility = Visibility.Hidden;
}
//do something
}
The part in the if statement is totally wrong, but i don't know how to go on on this point. can anyone push me a bit more in the right direction ?
thanx!
You can frame this requirement as "set the Visibility property of the various images to the same value", i.e. they all show/hide based on the same exact flag. WPF has some mechanisms that require a slightly different mindset than traditional imperative code, but can greatly simplify this scenario.
WPF supports the concept of databinding, which allows you to declare the images' dependency on a value instead of applying the value by hand. You can take advantage of this to manage the Visibility property values solely in markup.
The main thing to learn about is the DataContext property, which represents the object currently bound to a particular control. In this case, you can set the data context to a value of Visibility:
public MainWindow()
{
DataContext = Visibility.Hidden;
}
Once you do that, it cascades throughout the object tree, so all of the children of MainWindow inherit this same value. This means you can do this in your XAML:
<Image x:Name="IMx01y01W" Visibility="{Binding}" />
<Image x:Name="IMx23y73W" Visibility="{Binding}" />
That tells WPF that you want the Visibility property to reflect the value of the current DataContext, which will be the Visibility.Hidden value you set in the constructor.
The nice part about this is that if you change the value of the DataContext property, it will automatically be reflected in all your images without any extra work:
private void MakeImagesVisible()
{
DataContext = Visibility.Visible;
// At this point, all images will be visible
}
The key takeaway is that WPF does things in a different way than traditional UI paradigms such as Windows Forms. Learning the philosophy behind these new techniques, rather than replicating legacy techniques, will help make WPF easier to understand and bend to your will.
Yes there is. You can get all children of a container control and filter for a particular type, images in your case, and perform actions on those instances. See this forum post for a sample. And this SO post. And this one.
For EDIT 1:
foreach (object obj in LogicalTreeHelper.GetChildren(this))
{
if (obj is Image)
{
Image img = (Image)obj;
img.Visibility = Visibility.Hidden;
}
}
One thing that you can do is
IMx01y01W.Visibility = IMx23y73W.Visibility = ... = Visibility.Hidden;
but I wouldn't call this any more readable.
What you could do instead is create a collection of IMx01y01W objects (of their base class) and iterate through that collection settings Visibility to Hidden.

MenuItem keyboard shortcuts in 'pure' MVVM?

All menus/contextmenus/toolbars I use in wpf are declared in ViewModel code pretty much like this:
MenuService.Add( new MenuItem()
{
Header = "DoStuff",
Command = new relayCommand( DoStuff, () => CanDoStuffExecute() )
// some more properties like parent item/image/...
} );
The MenuService provides a single binding point which is a hierarchical list of MenuItem and gets bound to the actual Menu's ItemsSource in xaml.
This works very well and now I'd like to add keyboard shortcuts in the same convenient way.
Ideally MenuItem would get a property of type System.Windows.Input.KeyGesture so I can simply write
Shortcut = new KeyGesture( Key.D, ModifierKeys.Control )
which would result in the Command of the item being called upon hitting Ctrl+D in the window that owns the menu, and which would also lead to automatically display "Ctrl+D" in the menu.
However I'm lost here: I wanted to set the MenuItem.InputBindings collection via databinding but it is get-only. How can I get items into it anyway? Or is there an MVVM framework that already supports something like this? Most q&a I found on keyboard shortcuts are all about setting the shortcuts through xaml, which is of no help.
Update
Searching for 'relaycommand vs routeduicommand and 'relaycommand keygesture' etc did reveal enough information to come up with a working though hacky solution. There are definitely other and better ways out there, but at the moment this is ultra low priority for me and does the job perfectly. I added two properties to the MenuItem class like this:
//Upon setting a Gesture, the original command is replaced with a RoutedCommand
//since that automatically gives us proper display of the keyboard shortcut.
//The RoutedCommand simply calls back into the original Command.
//It also sets the CommandBinding property, which still has to be added to the
//CommandBindingCollection of either the bound control or one of it ancestors
public InputGesture Gesture
{
set
{
var origCmd = Command;
if( origCmd == null )
return;
var routedCmd = new RoutedCommand( Header,
typeof( System.Windows.Controls.MenuItem ),
new InputGestureCollection { value } );
CommandBinding = new CommandBinding( routedCmd,
( sender, args ) => origCmd.Execute( args.Parameter ),
( sender, args ) => { args.CanExecute = origCmd.CanExecute( args.Parameter ); } );
Command = routedCmd;
}
}
//CommandBinding created when setting Gesture
public CommandBinding CommandBinding { get; private set; }
So this gives the functionality I asked for originally (ie adding keyboard shortcuts in code where they are easily configurable etc). All that is left is to register the commandbindings. At the moment this is done simply by adding all of them to Application.Current.MainWindow.CommandBindings.
This doesn't actually qualify as an 'answer' (I'm not able to add a comment evidently) - but I'd suggest that what you're doing, is not the intended method in WPF. You're doing this the Windows Forms way (and as in many other toolkits) - defining your UX in code. You got as far as you did, but now you've run into a brick wall: the key gestures are purely UX, definitely not to be specified in code-behind. The appearance (as a function of the view-model), and the user's interaction with it (ways of making a given command happen) are for the XAML definition.
Property values, and Commands are for your view-model, so that you can reuse this view-model for other views, and also easily create unit-tests for it. How would implementing your keyboard shortcuts in the view-model help the testability? And for use in other views, one could argue that the actual shortcuts might not apply to a new view, so that is not where those belong. You may have other reasons of course - but I'd suggest you might consider just defining these in XAML.
-Added, in response to your comment-
You're quite right - and I've seen some rather large WPF UX projects that tried hard to avoid any code-and wound up unnecessarily obtuse. I try to just use whichever approach yields a working result, and is as simple as I can get it.
Here is a sample snippet that simply creates the MenuItem..
<Menu x:Name="miMain" DockPanel.Dock="Top">
<MenuItem Command="{Binding Path=MyGreatCommand}" Header="DoSomething"/>
That creates the menu. Here, MyGreatCommand is an ICommand, and is simply a property on the view-model. I generally place that within a DockPanel, to handle the StatusBar, etc.
To assign the key gesture..
<Window.InputBindings>
<KeyBinding Key="X" Modifiers="ALT" Command="{Binding Path=MyGreatCommand}"/>
However, since you mentioned that you've already searched for answers and found only XAML - I assume you've already tried this approach. I have used RoutedUICommands instead of user-defined ICommands, to get that nice right-aligned key-gesture in the header text, but I haven't found how to do both. If you insist upon creating the commands and key-gestures all in code, you may have to create RoutedUICommands.
Why are you wanting to set the key-gestures in other than your XAML?
If you want some menu-items to appear only when certain states hold sway within your view-model, then you can bind the Visibility property of a menu-item (which can contain other menu-items) to Collapsed or Visible.

Interactive Design-Time User Control

I apologise if the title was confusing, it took me nearly 5 minutes to finally think of a title for this one...
Okay, you know how in Visual Studio Express when you add a TabControl to the Form, and you can click on the right-arrow on the top right of the TabControl and it will add a new TabPage, or remove one?
Well, I'm creating a User Control where I need people to be able to switch between Panels (my user control is made up of several Panels). I know this is possible as I've used a Ribbon Control in the past and you could add new buttons etc in the Designer View.
Can somebody please provide any suggestions/advice on how I might go about acheiving this?
Thank you
If I understand your question correctly, you're talking about smart tags.
The process is a little bit involved, so I'm not going to try to post a complete sample. Instead, I'll refer you to this tutorial on the subject. To make a long story short, you have to create a custom designer, and register one or more custom actions. You can use this to create a combo box listing the available panels and switch between them when the selected item is changed.
(Note - the term "smart tags" has two distinct meanings in Visual Studio - I'm specifically talking about the visual designer smart tags, not smart tags in the code editor).
When you make a control that is inherited from Control, you have to make use of a couple of properties such as IsDesignMode, you can then construct event handlers especially for within Design Mode:
if (IsDesignMode){
// Handle the interactivity in Design mode, such as changing a property on the
// Properties toolbox
}
Suppose the control has an event such as MouseClick, you can do this:
private void control_MouseClick(object sender, MouseEventArgs e){
if (IsDesignMode){
// Do something here depending on the Click event within the Designer
}else{
// This is at run-time...
}
}
Another I can think of is 'ShouldSerialize' followed by a publicly accessible property in order to persist the property to the designer-generated code, suppose for example a Control has a boolean property Foo
public bool Foo{
get{ return this._foo; }
set{ if (this._foo != value){
this._foo = value;
}
}
}
public bool ShouldSerializeFoo(){
return true; // The property will be persisted in the designer-generated code
// Check in Form.Designer.cs...
}
If ShouldSerializeFoo returned false, no property is persisted, its the opposite when true, it will be buried within the Form.Designer.cs code...
Hope this helps,
Best regards,
Tom.

How to Find Children of a UserControl instead of a Window - replacing Window.FindName

I currently have a WPF project which has one main Window, and many UserControls which are children of this Window. Many of the children of this window are Tabs. I have successfully replaced my main Window with a User Control that implements almost exactly the same functionality as the Main Window.
Replacing the Window with a UserControl introduced one problem - currently our application determines which programming tab to display based on the parent window by using the Window.FindName method shown below. Therefore I need to replace the Application.Current.MainWindow with an appropriate description of my main user control. See the erroring C# method below and wpf instantiation of the tabs for clarification.
Note Regarding Window.FindName() method - the reason why it does not work after I replaced it with a UserControl is because the FindName method searches upwards in the visual tree, as described here.
Does anyone know how to find a user control based on the x:Name, similar to Application.Current.MainWindow ? Also, is there a better way to find the UserControl than looking for the x:Name string in case it gets renamed?
How we currently find the MainWindow - need to now find MainUserControl:
(C#)
private static void SetCurrentProgram(int num)
{
Window window = Application.Current.MainWindow;
ProgrammingTab programmingTab1 = window.FindName("ProgrammingTab1") as ProgrammingTab;
ProgrammingTab programmingTab2 = window.FindName("ProgrammingTab2") as ProgrammingTab;
programmingTab1.Visibility = num == 1 ? Visibility.Visible : Visibility.Collapsed;
programmingTab2.Visibility = num == 2 ? Visibility.Visible : Visibility.Collapsed;
}
Instantiation of programming tabs.
(xaml)
<Grid>
<ProgrammingControl:ProgrammingTab x:Name="ProgrammingTab1" Program="1" IsVisibleChanged="ProgrammingTab_IsVisibleChanged" />
<ProgrammingControl:ProgrammingTab x:Name="ProgrammingTab2" Program="2" IsVisibleChanged="ProgrammingTab_IsVisibleChanged" />
</Grid>
It sounds like your app is developed in a very WinForms-like style. To stick with that style and simply answer your question, you can FindName() to find the UserControl and again to find the ProgrammingTab, like this:
var userControl = (MyUserControl)Application.Current.MainWindow.FindName("userControlName");
var programmingTab1 = (ProgrammingTab)userControl.FindName("ProgrammingTab1");
var programmingTab2 = (ProgrammingTab)userControl.FindName("ProgrammingTab2");
...
However I would recommend you look into using WPF's advanced capabilities such as data binding. You can have a DependencyProperty "CurrentProgram" on a singleton object referenced by a static property, and simply databind Visiblity to it using a converter.
<ProgrammingTab Visibilty="{Binding CurrentProgram,
Source={x:Static MyState.Instance},
Converter={x:Static VisibleIfEqualConverter},
ConverterParameter=1}" ...>
...
With this change, your SetCurrentProgram becomes simply:
public void SetCurrentProgram(int num)
{
MyState.Instance.CurrentProgram = num;
}
The beauty of this technique is that any ProgrammingTab anywhere in your application will automatically appear or disappear every time MyState.Instance.CurrentProgram's vaulue changes, with no need to find them with FindName() or otherwise.
I figured out a workaround to this problem: I created a new algorithm based on another StackOverflow user's algorithm that recursively found any children of a DependencyObject. Find my solution here. If you declare the FindChild() method in my other post within public static class UIHelper {} you can then solve the problem by doing this:
ProgrammingTab programmingTab1 = UIHelper.FindChild<ProgrammingTab>(Application.Current.MainWindow, "ProgrammingTab1");
ProgrammingTab programmingTab2 = UIHelper.FindChild<ProgrammingTab>(Application.Current.MainWindow, "ProgrammingTab2");
This still uses procedural code instead of declarative XAML for bindings like RayBurns suggested. If it works, his solution will be much more efficient as it wont be traversing a whole tree but rather just changing the visibility of tabs based on a converter. I'll test that solution now and see how it turns out.
The reason why FindName() doesn't work properly is described in the post here.
This article may helps you : http://blog.lexique-du-net.com/index.php?post/2010/09/14/UserControl/Control-how-to-get-a-reference-to-an-element-of-the-template

Categories