I have a context menu and checkbox inside it, but checkbox displays not correctly.
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu >
<toolkit:MenuItem Click="iLikeIt" Tag="{Binding ElementName=chbox}" Header="{Binding isLikeMe, Converter={StaticResource LikeIt}}"/>
<toolkit:MenuItem>
<toolkit:MenuItem.Header>
<CheckBox Name="chbox" Tag="{Binding}" BorderThickness="1" Content="Рассказать друзьям" >
</CheckBox>
</toolkit:MenuItem.Header>
</toolkit:MenuItem>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
As this is a UI issue and not a functional one this is very likely a styling issue with the CheckBox. You will need to apply a custom style to the CheckBox in the ContextMenu so that it looks OK in the inverted colours of the ContextMenu.
Make sure you make it work in both Dark and Light theme though.
Related
I wrote an example application that highlights the issue, which might have to do with focus-scope because it's whenever a ToolBar is involved and a UserControl is unloaded when switching tabs.
The main window contains a Menu with a File->New command and a TabControl that displays a collection of "Box" instances:
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Command="New"/>
</MenuItem>
</Menu>
<TabControl ItemsSource="{Binding Boxes}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Width="40"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<local:BoxView/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</DockPanel>
Each "Box" instance has a Name property displayed in the tab header, and the rest of it is displayed in a "BoxView" UserControl. The "BoxView" has a ToolBar, the first button of which becomes the focus hog in the mentioned use case. The "BoxView" also displays a collection of "Compartments" that are inside each "Box" instance:
<StackPanel>
<ToolBarTray IsLocked="True">
<ToolBar>
<Button Content="Focus hog"/>
</ToolBar>
</ToolBarTray>
<ItemsControl ItemsSource="{Binding Compartments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:CompartmentView/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Each "Compartment" instance has a TotalValue property simply displayed in a TextBox in a "CompartmentView" UserControl:
<StackPanel>
<TextBox Text="{Binding TotalValue}"/>
</StackPanel>
And the problem is...
If I click on the TextBox of any one of the CompartmentView's, and then click a different tab of the main window, the first button of the ToolBar of the BoxView is focused (the focus hog one), disabling commands working in the main window.
It can be observed commands are disabled when opening the File menu. But after closing the menu and reopening, commands are enabled again.
How do I prevent the ToolBar in the nested UserControl from being focused when switching tabs?
Or perhaps I'm going at this wrong... how do I prevent focus from being set when switching tabs?
Update
The following link is a video on youtube where I explain the problem with the application.
https://youtu.be/0T5LK3CYxgw
Solution update
Thanks to themightylc for the answer, the issue was clearly a keyboard focus problem when the focused visual control (any selected "CompartmentView" or "BoxView" control) was unloaded while changing the selected tab in the TabControl. The solution was to focus on the TabControl itself in the main window whenever the tab selection changed:
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
(sender as TabControl).Focus();
}
Thanks also to Christoph Nahr's response for the solution on this msdn thread: https://social.msdn.microsoft.com/Forums/vstudio/en-US/f5de6ffc-fa03-4f08-87e9-77bbad752033/a-focusscope-nightmare-bug-commands-are-disabled?forum=wpf
<Button Content="Focus hog" Focusable="False" />
This solves the problem you're having. Focusable is a DependencyProperty If you still want to access the ToolBar via Keyboard-Focus, you can bind it or set it from code-behind when the Tab-Switch is complete.
You can of course set it via Style so you don't have to set it on every element of the ToolBar.
I encountered a problem when I was developing a WPF application with a TabControl object. I tried to debug and find the problem and finally I've got it, but I didn't find any workaround to it. Here is some explanation:
I used this data grid filtering library (here is a codeproject url), which is the best (from my viewpoint). I want to customize it with the google material design theme and change some graphical features, such as using a toggle button in the first tab header of data gird to hide/show the filtering option.
I created a user control and placed my custom datagrid in it. Then I embedded that control into the tabItem. When I set this control to the first tabItem, everything works correctly. But when I change the user control to the other tabItem, the toggle button does not work.
Here is my main window xaml code that didn't work:
<TabControl x:Name="tabControl">
<TabItem Header="1'st Tab">
<ContentControl DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Button Content="Do no thing"></Button>
</ContentControl>
</TabItem>
<TabItem Header="2'nd Tab">
<ContentControl DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<local:UserControl1/>
</ContentControl>
</TabItem>
</TabControl>
Note that if I change the order of TabItems, it works well. Does anyone have a suggestion how to solve this problem? Here is my sample project code on Github
Edit: Today, I test my application with "WPF Inspector" to find the structure of visual and logical tree. The behavior was too strange because when I attached "WPF Inspector" to my application, everything started to work. The below GIF is what I did:
When using a ContentControl for a Data-Object, in your case it's the data context, you bind the Content property to the Data-Object and specify the DataTemplate property. In this case the content within DataTemplate will have its DataContext set to your Data-Object.
Here is a working sample:
<TabControl x:Name="tabControl">
<TabItem Header="1'st Tab">
<ContentControl Content="{Binding .}">
<ContentControl.ContentTemplate>
<DataTemplate>
<Button Content="Do no thing"></Button>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</TabItem>
<TabItem Header="2'nd Tab">
<ContentControl Content="{Binding .}">
<ContentControl.ContentTemplate>
<DataTemplate>
<local:UserControl1/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</TabItem>
</TabControl>
I'm using Prism for Windows Runtime to wire up events in my Views with DelegateCommands in my ViewModels. I am wondering what would be the best way to invoke commands (e.g. select item) from a ListView that contains Buttons (or custom controls derived freom the Button class). I'd like to keep the effects (e.g. background change, tilt effect) provided by the Button control. But the button unfortunately absorbs the click events, which, in consequence, I cannot use in the ListView to hook up my commands e.g with the following XAML (and Behaviors SDK):
<ListView ItemsSource="{Binding AvailableItemsList}" SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<customControls:NavMenuButton Style="{StaticResource SelectionListMenuButton}" Content="{Binding Nickname}" DescriptionText="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="SelectionChanged">
<core:InvokeCommandAction Command="{Binding ItemSelectedCommand}" />
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
</ListView>
What would be the best way to achieve this? I have found similar questions, but the difference here is that the controls in the list items are apparently "stealing" the click event (while it works just fine with e.g. a simple TextBlock).
To close this question, here is the solution based on MatDev8's comment above (thank you!):
<ListView x:Name="myListView" ItemsSource="{Binding AvailableItemsList}" SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<customControls:CustomTextButton Style="{StaticResource SelectionListMenuButton}"
Content="{Binding Nickname}"
DescriptionText="{Binding Name}"
Command="{Binding DataContext.ItemSelectedCommand, ElementName=myListView}"
CommandParameter="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
To have the commands binding in ListView you can use buttons within the ListView.
now for the clicking related issue you can modify your button's Controltemplate to make it look like a simple textblock. this way your clicking will also work on the listview and it will not be displayed as button.
<ControlTemplate TargetType="Button">
<TextBlock Text="{TemplateBinding Content}" />
</ControlTemplate>
You can also customize the click event in other way like moving focus to the button should also raise your click event(indirectly fire your command). This will help in your case of Listview where just moving to next item should also fire the command.
My problem is twofold, but i guess that they are related, and if I manage to fix one of them, I will solve both.
First of, lets see the xaml code for a ContextMenu that is linked to a Caliburn.Micro view model:
<ContextMenu>
<MenuItem Header="Configure modem" ItemsSource="{Binding Modems}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ca:ActionMessage MethodName="SelectModem">
<ca:Parameter Value="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />
</ca:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
<MenuItem.Header>
<DockPanel>
<Image DockPanel.Dock="Left" Source="{Binding CarrierProfile.CarrierProfileIcon}" Width="40" Height="40"/>
<TextBlock Text="{Binding MenuText}" VerticalAlignment="Center" Margin="10 0"/>
</DockPanel>
</MenuItem.Header>
</MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
</ContextMenu>
So basically this is just a DataTemplate where I set the Header to a DockPanel containing an image and a TextBlock.
One MenuItem looks like this:
Here you can see the main problem. You can see that there are "two selections". One outer selection, and one inner. If I click the inner selection, everything is fine, and my SelectModem method is called from my view model. However, if you click the outer selection the context menu goes away so that user thinks he has made a selection, but actually no method is called on the view model.
My second problem is that if I disable the MenuItem by adding IsEnabled="False" in the code above, the menu item looks disabled (text is grayed out), I cannot make the inner selection, but on hover is still shows the outer selection, and when clicked the menu goes away (but nothing is triggered in my view model)
So the question is: How can I get rid of the the outer selection?
By default the expander has a left aligned toggle button but in my WPF app i want toggle button on the right side of the header without the help of Expression Blend. just plain XAML and/or C#. My expander contains a vertically oriented stackpanel which has labels as its child.
I went for its part but here it says "The Expander control does not have any named parts".
I found an example here. But it overrides the default Expander Style.
I think the attached image should convey what i want. How to do. Any link would be helpful.
There is a trick that can help
<Expander Header="My Expander"
FlowDirection="RightToLeft">
<Expander.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=Expander}, Path=Header}"
Width="{Binding RelativeSource={RelativeSource AncestorType=Expander}, Path=ActualWidth}"
Margin="-30,0,0,0"
FlowDirection="LeftToRight">
</TextBlock>
</DataTemplate>
</Expander.HeaderTemplate>
</Expander>
Use this:
<Expander Header="Expander1" FlowDirection="RightToLeft">
<TextBlock FlowDirection="LeftToRight">
</TextBlock>
</Expander>
Add your content in the TextBlock, if you don't want to the whole content to be right to left.