I have a WPF UserControl that I'm trying to adapt to my program with kind of a MVVM pattern. Now the problem is, that the UserControl uses Command- and InputBindings which I can't simply apply to a DataTemplate. What options do I have to implement the same functionality without even having a code-behind?
Here's the XAML as of right now:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyProject.Settings"
xmlns:elements="clr-namespace:MyProject.Settings.Elements"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:dataPresenter="http://infragistics.com/DataPresenter"
xmlns:igEditors="http://infragistics.com/Editors"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<DataTemplate x:Key="PrioritySettingTemplate" DataType="{x:Type elements:PrioritySetting}">
<ContentPresenter>
<ContentPresenter.InputBindings>
<KeyBinding Gesture="Delete" Key="Delete"
Command="{Binding TestCommand}" />
</ContentPresenter.InputBindings>
<ContentPresenter.ContentTemplate>
<DataTemplate DataType="{x:Type elements:PrioritySetting}">
<!--
Main part of the UserControl
-->
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</DataTemplate>
Related
When I define a DataTemplate inline, Visual Studio knows about the type I'm binding to, and properties in that type come up in autocomplete (for example in the code below I was able to select DisplayName from the autocomplete list inside the FirstViewModel template).
<DataTemplate DataType="{x:Type viewmodels:FirstViewModel}">
<StackPanel >
<Label Content="{Binding DisplayName}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:SecondViewModel}">
<views:SecondView/>
</DataTemplate>
However, when the data template references an external control, as for SecondViewModel in the code above, when I'm in the file for the SecondView usercontrol, since it's just a control, the type isn't bound and the editor doesn't help me with anything.
I've tried wrapping my whole control (inside the UserControl element) in the same DataTemplate tag, but then my whole view just shows "System.Windows.DataTemplate".
<UserControl x:Class="Gui.Views.Tabs.ExamsTabViews.ExamInfoView"
xmlns:vm="clr-namespace:Gui.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<DataTemplate DataType="vm:ExamInfoViewModel">
<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<!-- contents of the template -->
</DockPanel>
</DataTemplate>
</UserControl>
Is there a way to achieve this kind of binding for the editor?
<DataTemplate DataType="{x:Type viewmodels:SecondViewModel}">
<views:SecondView/>
</DataTemplate>
when this DataTemplate is instantiated, there will be created SecondView and that SecondView will have a SecondViewModel in DataContext. So there is no need any DataTemplate in SecondViewModel control - bind to DataContext instead ({Binding SecondViewModelProperty}). To have design-time support for such binding use d:DataContext="{d:DesignInstance}:
<UserControl d:DataContext="{d:DesignInstance Type=vm:ExamInfoViewModel,
IsDesignTimeCreatable=True}" ...>
<Window x:Class="App1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cust="clr-namespace:App1.Customers"
Title="Customers"
Height="525"
Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type cust:CustomerViewModel}">
<cust:CustomerView />
</DataTemplate>
</Window.Resources>
<Grid x:Name="MainContent">
<ContentControl Content="{Binding CurrentViewModel}" />
</Grid>
</Window>
I've declared the datatemplate above in xaml. Over time there could be 20 viewmodels and views the main window might need to know about. I'd rather pass responsibility for adding the datatemplate(s) to the resource dictionary to somewhere else. How can I achieve the above in c#? Just the bit which adds the datatemplate to the resource dictionary
My code:
<Window ...
Title="Notification" Height="90" Width="300" ResizeMode="NoResize" WindowStyle="None" DataContext="{Binding Notification, Source={StaticResource Locator}}" Opacity="{Binding TransitionOpacity}" Left="{Binding LeftMargin}" Top="{Binding TopMargin}" Visibility="{Binding IsVisible, Converter={StaticResource BoolToVisibility}}">
<Window.Resources>
<local:BoolToVisibleOrHidden x:Key="BoolToVisibility" />
</Window.Resources>
<Grid Background="#FF3C4759">
...
</Window>
While compiling I get exception System.Windows.Markup.XamlParseException and after change code to
<Window ...
Title="Notification" Height="90" Width="300" ResizeMode="NoResize" WindowStyle="None" DataContext="{Binding Notification, Source={StaticResource Locator}}" Opacity="{Binding TransitionOpacity}" Left="{Binding LeftMargin}" Top="{Binding TopMargin}" >
<Window.Resources>
<local:BoolToVisibleOrHidden x:Key="BoolToVisibility" />
</Window.Resources>
<Grid Background="#FF3C4759" Visibility="{Binding IsVisible, Converter={StaticResource BoolToVisibility}}">
...
</Window>
it works but I want to set Window visibility instead of Grid.
Binding window visibility might be not a good idea in this case. If you have a notification which you want to hide after some time - just close it (Close()) instead of hiding.
If however you still want to do this - put converter into your application ( App.xaml file). Then you will be able to use it in Window.Visibility binding. As of now - window Visibility property is set before Window.Resources are initialized, so you cannot use converter created inside Window.Resources.
Alternative way is to set Visibility like this:
<Window.Resources>
<local:BoolToVisibleOrHidden x:Key="BoolToVisibility" />
</Window.Resources>
<Window.Visibility>
<Binding Path="IsVisible" Converter="{StaticResource BoolToVisibility}" />
</Window.Visibility>
I have a MainWindow.xmal which has two TabItems:
<TabItem Header="Config" ... />
<TabItem Header="Results" ... />
I have a separated Config.xaml file for the Config TabItem which has a ListBox:
<ListBox Name="UrlConfig" ... />
I have another separated Results.xaml file for the Results TabItem which has a TaxtBlock:
<TextBlock Name="Url" .../>
The problem is that I'd like to bind the selected value in the ListBox to the TextBlock. How can I do that? Please help :)
I recomend you to work with MVVM, but if not you can implement it with XAML only:
Use sepparate resource like "Bridge" 'Config' and 'Results'
Config.xaml:
<UserControl x:Key="Config">
<ListBox x:Name="ListBox1" SelectedItem="{Binding Source={StaticResource SelectedValue}, Path=Y, Mode=TwoWay}" >
<System:String>Minsk</System:String>
<System:String>London</System:String>
<System:String>NY</System:String>
</ListBox>
</UserControl>
Results.xaml
<UserControl x:Key="Results">
<Label Name="Url" Content="{Binding Source={StaticResource SelectedValue}, Path=Y}" />
</UserControl>
Code of window with TabControl:
<Window.Resources>
<!--"Bridge" resource, here will be your own type-->
<X x:Key="SelectedValue" Y="Minsk"></X>
</Window.Resources>
<Grid>
<TabControl>
<TabItem Header="Config" Content="{StaticResource ResourceKey=Config}"/>
<TabItem Header="Results" Content="{StaticResource ResourceKey=Results}"/>
</TabControl>
</Grid>
If you're working in mvvm way you can bind those to a property on your viewmodel and set the DataContext for to that viewmodel
I am writing an application in which I utilize a tab control which will start with one tab open but allows the user to open multiple other tabs.
Each tab that is openned should have a treeview inside which I fill using databinding when the user loads a file.
I am new to WPF but I feel as if there is a way in which I can create a template containing each of the elements the TabItems should contain. How can I do this using templates? Right now my WPF for the tab items is the following
<TabItem Header="Survey 1">
<TreeView Height="461" Name="treeView1" VerticalAlignment="Top"
Width="625" Margin="0,0,6,0" ItemTemplateSelector="{StaticResource TreeviewDataSelector}" />
</TabItem>
I think you want something like this:
<Window x:Class="TestWpfApplication.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate x:Key="TabItemTemplate">
<TreeView Height="461" Name="treeView1" VerticalAlignment="Top"
Width="625" Margin="0,0,6,0" ItemTemplateSelector="{StaticResource TreeviewDataSelector}" />
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl ItemsSource="{Binding ListThatPowersTheTabs}"
ItemTemplate="{StaticResource TabItemTemplate}">
</TabControl>
</Grid>
You basically create re-usable templates as static resources which you refer to by their key name.
Usually in this sort of situation I bind my TabControl.ItemsSource to a ObservableCollect<ViewModelBase> OpenTabs, so my ViewModel is in charge of adding/removing new tabs as needed.
Then if you want something in every Tab, then overwrite the TabControl.ItemTemplate and use the following line to specify where to display the currently selected TabItem
<ContentControl Content="{Binding }" />
If you don't need to setup something in every single tab, you don't need to overwrite the TabControl.ItemTemplate - it will default to displaying the currently selected ViewModelBase in the Tab.
And I use DataTemplates to specify which View to use
<DataTemplate TargetType="{x:Type local:TabAViewModel}">
<local:TabAView />
</DataTemplate>
<DataTemplate TargetType="{x:Type local:TabBViewModel}">
<local:TabBView />
</DataTemplate>
<DataTemplate TargetType="{x:Type local:TabCViewModel}">
<local:TabCView />
</DataTemplate>