Command Binding with WPF - c#

Im a complete Noob to this so im having a really hard time wrapping my head around how this works.
Basically I have a Main Page that im using, and within the XAML i have created a menu
What I have is a Document (DummyDoc) that contains a TextBox within it that i am trying to send the find command to.
Ive tried this every which way and googled it but i just cant seem to get it to work for me and could use some help with a push in the right direction
Main form
<Window>
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:DMC_Robot_Editor"
xmlns:local="clr-namespace:DMC_Robot_Editor.GUI"
<Menu>
<MenuItem Header="_Edit">
<MenuItem Header="_Cut"/>
</MenuItem>
<MenuItem/>
<Grid>
<local:DummyDoc x:Name="_Editor"/>
</Grid>
</Window>
That is the main form that i am using. then i have my second document "DummyDoc"
<ad:DocumentContent x:Name="document" x:Class="DMC_Robot_Editor.Controls.DummyDoc"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock"
xmlns:local="clr-namespace:DMC_Robot_Editor.Controls"
xmlns:ed="schemas.microsoft.com/expression/2010/drawing"
Title="Window1" Height="300" Width="300"
IsVisibleChanged="Is_VisibleChanged" PropertyChanged="document_PropertyChanged">
<Grid>
<Menu >
<MenuItem Header="_File">
<MenuItem Header="was here"/>
</MenuItem>
</Menu>
<local:Editor x:Name="source" IsVisibleChanged="Is_VisibleChanged" TextChanged="TextChanged" UpdateFunctions="raiseupdated" />
<local:Editor x:Name="data" Visibility="Hidden" IsVisibleChanged="Is_VisibleChanged" TextChanged="TextChanged" UpdateFunctions="raiseupdated"/>
</Grid>
</ad:DocumentContent>
DummyDoc is a window that has an Inherited Editor in it.
<avalonedit:TextEditor
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
x:Class="DMC_Robot_Editor.Controls.Editor"
x:Name="editor"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300"
TextChanged="Text_Changed"
IsVisibleChanged="raiseUpdate"
MouseMove="Mouse_Move"
MouseHover="Mouse_Hover"
MouseHoverStopped="Mouse_Hover_Stopped" KeyUp="editor_KeyUp">
</avalonedit:TextEditor>
My Ultimate Question is how do i use WPF Binding to make the "Cut" Action from the main form initiate the cut() method of the textbox?
I wrote textbox in it because in code behind, im doing the following
partial class DummyDoc:DocumentContent
{
public Editor TextBox{get;set;}
private void Is_VisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (sender is Editor)
this.TextBox = sender as Editor;
if ((VisibilityChanged != null) && (TextBox != null))
raiseupdated(TextBox, new FunctionEventArgs(this.TextBox.Text));
}
}

ElementName looks up elements by looking for an element which is using the string identifier you specify.
Did you put x:Name="local:TextBox" on your TextBox tag?
I think you've got your wires crossed by using "local:TextBox".
For starters...that is the syntax used to refer to an element type within a namespace .... it means "the type TextBox in the local namespace".....it's not valid (or rather doesn't mean the same) in the context you are using....you should just assign an "identifier" string.
So....
CommandTarget="{Binding ElementName=textboxFind}"
...
<TextBox x:Name="textboxFind" ..... />
would be more appropriate.
UPDATE (in light of question being clarified):
You should specify a "Command" in your menu item which will get raised when you choose that menu item.
Then if the TextEditor has the focus (...and thus is the command target...)....then it should see the Cut command.
I would expect the Avalon Editor to be able to handle the well know "ApplicationCommands" i.e. Cut, Copy, Paste, etc.
<MenuItem Header="_Cut" Command="ApplicationCommands.Cut">

Related

WPF command bindings in user controls not working

I've tried pretty hard to find a solution by myself searching the web and following examples but everything I've tried until now has failed. I know that my poor experience with WPF is making me missing something huge and silly but as a matter of fact I'm stuck.
As written in the object, I have a custom UserControl that contains a RadioButton. I want to 'expose' the Command of the RadioButton outside through a DependencyProperty of my UserControl.
The .xaml of the UserControl (named 'ImageRadioButton') is the following:
<UserControl x:Class="WpfSinergoHMIControls.Controlli.ImageRadioButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
</UserControl.Resources>
<Grid>
<Grid>
<RadioButton Command="{Binding SomeCommand, ElementName=me}" Name="button1" Foreground="White">
</RadioButton>
</Grid>
</Grid>
</UserControl>
the dependency property in the UserControl program file is the following:
public static readonly DependencyProperty SomeCommandProperty =
DependencyProperty.Register(
"SomeCommand",
typeof(ICommand),
typeof(ImageRadioButton),
new UIPropertyMetadata(null));
public ICommand SomeCommand
{
get { return (ICommand)GetValue(SomeCommandProperty); }
set { SetValue(SomeCommandProperty, value); }
}
Finally I declare in the application that uses my UserControl an istance:
<Controlli:ImageRadioButton x:Name="btnAutomatic" GroupName="MainMenu" SomeCommand="{Binding DataContext.NavigateAutomaticCommand, ElementName=MainViewObj}" HorizontalAlignment="Left" Height="60" VerticalAlignment="Bottom" Width="140" Canvas.Left="1373" Canvas.Top="5" Margin="6,0,0,5" IsChecked="True"/>
worthless to say that this doesn't work (no command is called). I know that there is something silly that I'm missing but after a lot of trials/searching I still cannot find the solution.
Thanks!
You reference the element me in your command binding, but you do not assign that name anywhere, which means that the binding source (your UserControl) cannot be found at runtime.
Command="{Binding SomeCommand, ElementName=me}"
If you set the name on your UserControl everything works as expected (at least for me).
<UserControl x:Class="WpfSinergoHMIControls.Controlli.ImageRadioButton"
...
x:Name="me">

changing text in parent UserControl from Child UserControl WPF

If a ParentUserControl contains a TextBlock. The ParentUserControlalso contains ChildUserControl that has a TextBox. I want to set the TextBlock of ParentUserControl value from ChildTextBox. how can i ?
In other words somehow accessing the ParentUserControl and it's TextBlock element and then modifying it's value from ChildUserControl !
Update
i have a xaml window that contains a ParentUserControl that has a TextBlock. Now i am loading or adding another ChildUserControl into it on runtime. This newly added ChildUserControl contains a ChildTextBox. Now i want that when i input some value into this ChildTexBox the ParentUserControl's TextBlock should get that value and update itself.
Assuming we are not following any MVVM and a simple approach for this problem is,
Create a ChildUserControl with a textbox inside it as below,
<UserControl x:Class="SO52840402.ChildUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SO52607887"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBox x:Name="ChildTextBox" />
</Grid> </UserControl>
Create a ParentUserControl which contains a TextBlock and ChildUserControl instance as shown below,
<UserControl x:Class="SO52840402.ParentUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SO52607887"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock x:Name="ParentTextBlock" Text="Hallo World!"/>
<local:ChildUserControl x:Name="ChildUserControl" Grid.Row="1" />
</Grid> </UserControl>
Now create a TextChanged event for the TextBox which is under ChildUserControl from code behind of ParentUserControl constructor after "InitializeComponent" as shown below,
public ParentUserControl()
{
InitializeComponent();
ChildUserControl.ChildTextBox.TextChanged += OnChildTextBox_TextChanged;
}
private void OnChildTextBox_TextChanged(object sender, EventArgs e)
{
ParentTextBlock.Text = (sender as TextBox).Text;
}
Note:- This is a not a recommended approach. For best approach, follow MVVM pattern and understand your requirements and do the design. Since you need something from a child user control from a parent user control, a best approach is to have a ViewModel bind to parent and child and access child view model in parent viewmodel and do "what ever you want".

ComboBox databinding to window background

Very new to WPF and c# here. I'm interested in having a ComboBox with different color options that will update the window's Background when an option is selected.
I want to do this via DataBinding, but I'm a noob and can't get it right. This is what I have.
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Background="{Binding SelectedValue,ElementName=combo,UpdateSourceTrigger=PropertyChanged}">
<StackPanel>
<ComboBox Name="combo">
<ComboBoxItem>lightcoral</ComboBoxItem>
<ComboBoxItem>khaki</ComboBoxItem>
</ComboBox>
</StackPanel>
</Window>
And the default MainWindow.xaml.cs (I haven't touched it since I created the project)
Thanks, let me know if you need any more info!
One possible way to achieve this is to put items of type string in your ComboBox, as opposed to ComboBoxItems:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Background="{Binding SelectedItem, ElementName=combo}">
<ComboBox VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="combo">
<sys:String>Yellow</sys:String>
<sys:String>Green</sys:String>
<sys:String>Red</sys:String>
<sys:String>Blue</sys:String>
</ComboBox>
</Window>
Notice that I declared the xmlns:sys XAML Namespace that points to the System CLR namespace in the mscorlib.dll assembly. This is where the class System.String is defined, and you need that to be able to use the class in XAML.
Also notice that I'm binding to SelectedItem as opposed to SelectedValue, this is because your ComboBox does not have SelectedValuePath, and WPF doesn't have the notion of the SelectedValue because it does not know how to "retrieve the value" from each of it's items.
Also notice that UpdateSourceTrigger is removed because it does not make any sense. UpdateSourceTrigger determines the way the Binding source is updated, not the target. Read about DataBinding on MSDN to understand the terminology here.
The reason that using a String works and using a ComboBoxItem does not is because the default Type Converter for the Brush class (which is the type of the Window's Background) "understands" how to convert from a string, but not from a ComboBoxItem.

View is not being resolved with Toolbar ItemsSource

It doesn't seem like the Caliburn Micro framework is retrieving my SinglePaintToolbarView when it is binded as a list of buttons in the toolbar of the ShellView. I would like the buttons to just display their text content when they are added to the toolbar. But, instead I'm getting this:
There doesn't appear to be any clickable buttons in the toolbar. I know my plugins are being loaded successfully, because I was able to bind one of the plugins in the list as a ContentControl and the view appeared. It just doesn't seem to work when I try to bind a list of the plugins in a toolbar.
Here is what I have:
ShellView.xaml
<UserControl x:Class="Starbolt.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<ToolBarTray>
<ToolBar ItemsSource="{Binding Path=ToolbarPlugins}"/>
</ToolBarTray>
</Grid>
</UserControl>
ShellViewModel.cs
[Export(typeof(IShell))]
public class ShellViewModel : PropertyChangedBase, IShell
{
[ImportMany(typeof(IToolbarPlugin))]
private IEnumerable<IToolbarPlugin> _toolbarPlugins = null;
public IEnumerable<IToolbarPlugin> ToolbarPlugins { get { return _toolbarPlugins; } }
}
SinglePaintToolbarView.xaml
<UserControl x:Class="Starbolt.Plugin.SinglePaintTool.Views.SinglePaintToolView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="128" d:DesignWidth="32">
<Button Name="btnSinglePaintTool" Content="Single Paint Tool" Width="128" Height="32"/>
</UserControl>
SinglePaintToolViewModel.cs
[Export(typeof(IToolbarPlugin))]
public class SinglePaintToolViewModel : IToolbarPlugin
{
}
Basically, your design seems to be working. If you replace
<ToolBarTray>
<ToolBar x:Name="ToolbarPlugins"/>
</ToolBarTray>
(note that you do not need to bind the ItemsSource explicitly, you can just as well use the Caliburn Micro property name conventions) with the following:
<ListBox x:Name="ToolbarPlugins"/>
the SinglePaintToolView button is displayed as intended.
I suspect that the problem is with the ToolBar ControlTemplate, which most certainly restricts the toolbar items layout more than what for example a ListBox ControlTemplate does.
So my guess is that if you really want to use the ToolBar control to display your IToolbarPlugin views, you will probably have to design a dedicated ToolBar control template in your project.
Alternatively, you could implement a toolbar replacement using e.g. ListBox. This could be a start:
<ListBox x:Name="ToolbarPlugins">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

How to use a ContextMenu UserControl in WPF?

I have a user control like this:
<UserControl x:Class="MyApp.UserControls.MyContextMenu"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
ContextMenuOpening="OnContextMenuOpening"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.ContextMenu>
<ContextMenu>
...
</ContextMenu>
</UserControl.ContextMenu>
</UserControl>
My question is: how do I use that context menu for something like a data grid:
<DataGrid ContextMenu="{usercontrols:MyContextMenu}"
Unfortunately that does not work because the specified value is incorrect and expected a ContextMenu.
Note: I need to reuse my context menu in several places, so I have put it in its own file. Also, I need to be able to listen to OnContextMenuOpening events, because the menu upon opening needs to do some work regarding the menu and the event is not fired for the context menu sadly: http://connect.microsoft.com/VisualStudio/feedback/details/353112/contextmenu-opening-event-doesnt-fire-properly
"ContextMenu itself is a FrameworkElement derived class, but this
event will not be raised from the context menu being opened as a
source. The event is raised from the element that "owns" the context
menu as a property and is only raised when a user attempts to open a
context menu in the UI."
This event problem is the reason I have put the menu for a user control -- so that the user control can get the event and do the work.
Update: I tried to have it as a root element and extend the context menu:
And code-behind:
But I'm getting: ContextMenu cannot have a logical or visual parent.
Regardless of how you call your UserControl, it is not a ContextMenu. You would have to derive from ContextMenu instead of UserControl:
<ContextMenu x:Class="MyApp.MyContextMenu"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<MenuItem Header="Item 1"/>
<MenuItem Header="Item 2"/>
...
</ContextMenu>
and
public partial class MyContextMenu : ContextMenu
{
public MyContextMenu()
{
InitializeComponent();
}
}
But why would you do that at all?
Try to defineit like:
<DataGrid.Resources>
<ContextMenu x:Key="DgContextMenu">
...
</ContextMenu>
</DataGrid.Resources>
and after use it like
<DataGrid ContextMenu="{StaticResource DgContextMenu}
Should work.

Categories