Okay. So I want my application to display in its main menu the "Save" and "Save As..." items just like Visual Studio does; i.e. "Save {current file}" and "Save {current file} As..."
I would also like to have the normal access keys ("S" and "A", respectively).
I've come up with two solutions, but neither is very desirable.
Instead of creating the main menu exclusively in xaml, I could
create it all in the MainWindowViewModel so I'd have full control over what goes into the generated MenuItems. However, I feel that this would be a violation of MVVM (which I'm attempting to abide by very strictly this time around) as I would have to include references to each MenuItem's Icon in the ViewModel. Plus it seems a little messy.
I can stipulate the header of just these two specific MenuItems (and perhaps future ones) like so, but then I end up getting a MenuItem that not only has a underscore in the header, but also does not contain an access key.
<MenuItem Header="{Binding CurrentFileName}"
HeaderStringFormat="Save {0} _As...">
What should I do?
Whelp, figured it out. At least about how to get it done with the whole main menu described in XAML. Just made the header content an AccessText control instead of a string and it works like a charm.
<MenuItem>
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding HasSelection}" Value="false">
<Setter Property="IsEnabled" Value="false"/>
<Setter Property="Header">
<Setter.Value>
<AccessText Text="Save Selected File _As..."/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding HasSelection}" Value="true">
<Setter Property="IsEnabled" Value="true"/>
<Setter Property="Header">
<Setter.Value>
<AccessText Text="{Binding SelectedFile.Filename, StringFormat=Save {0} _As...}"/>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
Related
All around my project I'm facing similar problem, which is "Enter" key, creating new line in cell, instead of move to next line.
My current telerik version is 2018.1.122.45, and default, expected behavior is to leave cell, after pressing "Enter" key (according to telerik documentation, and helpdesk).
However, in my case it always makes new line within cell being edited.
I'm using Visual Studio 2013 theme, my implementation of RadGridView is correct, I've pasted my RadGridView, to project, I got from telerik support, and there, Enter was working as expected. Also, they've pasted my RadGridView implementation to their project and it also worked correctly.
Have anyone faced similar problem? I'm looking for solution, since I can't track source of this issue (even with teleriks help).
I've found a solution to this problem, and other Styles problems. Implementing style in the way demonstrated in telerik documentation (f.e. https://docs.telerik.com/devtools/wpf/controls/radgridview/styles-and-templates/styling-a-row) has some issues not mentioned in documentation.
<Style TargetType="telerik:GridViewRow">
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="White"/>
</Style>
This is one of the simpliest examples of implementing style. In my case it was:
<Style TargetType="telerik:GridViewCell"
x:Key="IloscNormalStyle"
BasedOn="{StaticResource GridViewCellStyle}">
<Setter Property="Background"
Value="#c3d8c7" />
<Setter Property="Foreground"
Value="Black" />
</Style>
And it works just fine. The biggest issue is that it completly ignores implemented Theme for project and all it's behaviours, which are, for example, selection behavior, enter key press, borders, etc. In order to tell style to not ignore implemented theme, I needed to insert this code to my styles:
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=telerik:GridViewRow}}"
Value="True">
<Setter Property="Background"
Value="{Binding Background}" />
</DataTrigger>
</Style.Triggers>
Which finally made my style works with desired behavior. Full style code:
<Style TargetType="telerik:GridViewCell"
x:Key="IloscNormalStyle"
BasedOn="{StaticResource GridViewCellStyle}">
<Setter Property="Background"
Value="#c3d8c7" />
<Setter Property="Foreground"
Value="Black" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=telerik:GridViewRow}}"
Value="True">
<Setter Property="Background"
Value="{Binding Background}" />
</DataTrigger>
</Style.Triggers>
</Style>
I think it is a major issue for telerik (or maybe even WPF), but this couple lines of code resolves most of problems with custom cell/row styling.
I want to define triggers as resources to use them later in my controls.
Like this:
<Window.Resources>
<DataTrigger x:Key="Trigger1" Binding="{Binding ViewModelProperty1}" Value="Val1">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
<DataTrigger x:Key="Trigger2" Binding="{Binding ViewModelProperty2}" Value="Val2">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
...
</Window.Resources>
However, when I try to run the code, the compiler complains that IsEnabled is not a valid member. I think this is because it cannot know if the control in question will even have the property "IsEnabled". Like with styles, I think I need to somehow specifiy the TargetType (which would be, in my case, FrameworkElement). But how?
NOTE:
Please do not suggest to use styles instead of triggers as resources. Since a control can only have ONE style, but I need to give SEVERAL triggers to one control, styles are no option here:
In my actual code I have a Button that should have trigger 1, 2 and 4 and a TextBox that should have trigger 1 and 3 and a Label that should have trigger 2, 3 and 4... I think you get it.
You can do it like this (note how I prepend IsEnabled with FrameworkElement and also how I reference those resources from style triggers):
<Window.Resources>
<DataTrigger x:Key="Trigger1"
Binding="{Binding ViewModelProperty1}"
Value="Val1">
<Setter Property="FrameworkElement.IsEnabled"
Value="False" />
</DataTrigger>
<DataTrigger x:Key="Trigger2"
Binding="{Binding ViewModelProperty2}"
Value="Val2">
<Setter Property="FrameworkElement.IsEnabled"
Value="False" />
</DataTrigger>
</Window.Resources>
<Button>
<Button.Style>
<Style>
<Style.Triggers>
<StaticResource ResourceKey="Trigger1" />
<StaticResource ResourceKey="Trigger2" />
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I have written this code:
<Image>
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding MyProperty}" Value="Play">
<Setter Property="Source" Value="bin\debug\Tasto Play.jpeg"/>
</DataTrigger>
<DataTrigger Binding="{Binding MyProperty}" Value="Pause">
<Setter Property="Source" Value="bin\debug\Tasto Pause.jpeg"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
But when I run the debug an error comes out. The error is System.Windows.Baml2006.TypeConverterMarkupExtension.
MyProperty is string.
Can someone help me?
Thanks,
Jacopo.
I think that maybe is the MyProperty property type: if it is string, there is not problem, but if it is, an enum for instance, you must set the type:
<Image>
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding MyProperty}" Value="{x:Type namespace:EnumType.Play}">
<Setter Property="Source" Value="bin\debug\Tasto Play.jpeg"/>
</DataTrigger>
<DataTrigger Binding="{Binding MyProperty}" Value="{x:Type namespace:EnumType.Pause">
<Setter Property="Source" Value="bin\debug\Tasto Pause.jpeg"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
Maybe could be the setter property, source (I think) is of type Uri, maybe you are not formatting well the string, maybe you must use an absulute uri (for test), but I think it is not a well formatted string path, so the Xaml's converter couldn'd create correctly the Uri type.
Hope this could helps, or give you some idea.
For add an image as a resource in a project you have to click "Project" in the "Visual Studio Menu Bar" and click "properties of the project".
Then a window with various toolbars (like internet) will open in your screen.
Choose the "resources toolbar"
(view the image at http://i.stack.imgur.com/IjC0w.jpg)
and click the arrow near the "Add Resources" button that will be on the top of the window.
Click "Add existing file" and choose the file.
Then you go in the "Explore solution window" and open the "Debug folder" that will have the new resources.
Click with "the right button of mouse" on the new resources that you have added
and click on "Properties".
On the left of your screen will appear a "Properties window".
(view the image at http://i.stack.imgur.com/NqIc1.jpg)
You have to choose on "Compilating operations" the "Resources" item.
Now you can use your image as a resources in wpf.
I hope that this could helps.
Jacopo
I have a requirement where a where user can switch to view hierarchical data either as tree or as a text in datagrid or as FlowChart.
The user can do this by clicking a Toggle Button which say: Switch Mode. I want to do all this in such a way that it can be handled within the View only as ViewModel in all the three cases is the same.
How do I apply View to my ViewModel based on Trigger.
If the state of which view to show is saved in some enum property you could use a ContentControl and DataTriggers for example:
<ContentControl>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding ViewMode}" Value="TreeMode">
<Setter Property="Content">
<Setter.Value>
<uc:TreeModeView />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ViewMode}" Value="GridMode">
<Setter Property="Content">
<Setter.Value>
<uc:GridModeView />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
(As the style is only used in one place, by setting it directly as ContentControl.Style this will work, if you want to use it in more than one place you should set the ContentTemplate instead, because otherwise there will only be one view instance shared by all controls with the style which is not allowed by WPF (of course Content needs to be set to something for the template to be applied))
You could also bind directly to IsChecked of the ToggleButton using ElementName of course. The relevant values would then be True, False and {x:Null}.
H.B.'s answer is good, but there are scenarios where it's not quite so good.
If constructing the views (and their underlying view models) is expensive, then toggling the Content property will pay this expense every time the user changes the view.
In some scenarios, it makes sense to create both views in the same container (e.g. a Grid), and toggle their Visibility instead. If you use lazy evaluation in your view models, the expensive operations won't be conducted until the view becomes visible, and - importantly - they'll only be conducted the first time the view becomes visible. Once both views have been displayed, the user can toggle back and forth between views without reconstructing the underlying view models.
Edit:
I stand corrected, sort of: H.B.'s answer is not as good as it looked .
You can't use a style to set the Content property of a ContentControl to a UIElement. See this blog post for full details, but the long and short of it is that if you use H.B.'s approach, you'll get a runtime error.
You can set the ContentTemplate property, instead, e.g.:
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding ViewMode}"
Value="TreeMode">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<uc:TreeModeView/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ViewMode}"
Value="GridMode">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<uc:GridModeView/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
Here's what I'm trying to do:
<Style x:Key="TreeViewItemStyle">
<Setter Property="TreeViewItem.ContextMenu" Value="{StaticResource ContextMenu}" />
<Style.Triggers>
<Trigger Property="TreeViewItem.ContextMenu.IsOpen" Value="True">
<Setter Property="TreeViewItem.BitmapEffect">
<Setter.Value>
<OuterGlowBitmapEffect GlowColor="Yellow" GlowSize="2"/>
</Setter.Value>
</Setter>
</Trigger>
</Style>
...
But it is obviously not working because Property="TreeViewItem.ContextMenu.IsOpen" is not recognized. Any suggestions to what I need to change?
You can bind to the IsOpened property of the context menu using a DataTrigger:
<DataTrigger Binding="{Binding ContextMenu.IsOpen, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
Unfortunately, since all of the items in TreeView share the same ContextMenu, that will highlight all of them at once. There doesn't seem to be a property that lets you find out which FrameworkElement opened the ContextMenu.
You could handle the ContextMenuOpening and ContextMenuClosing events on the TreeViewItem, since those will bubble up from the control that handled the click and pass through the right TreeViewItem. If you want to do it in XAML, you could use an EventTrigger to start a one-frame animation that changes your property. The cleanest option may be to write an attached behavior that handles the ContextMenuOpening and ContextMenuClosing events and sets an attached property to true when the context menu is open.