i have build my own usercontrol template, the inherited class looks like:
using System.Windows.Controls;
using CustomCopyNas.Views;
namespace CustomCopyNas.MVVM
{
/// <summary>
/// Base class for all Views that is used in MVVM
/// </summary>
/// <typeparam name="TViewModel">ViewModel</typeparam>
public class ViewBase<TViewModel> : UserControl, IView<TViewModel> where TViewModel : UploadViewModelBase
{
public ViewBase()
{ }
public ViewBase(TViewModel tViewModel)
{
ViewModel = tViewModel;
}
/// <summary>
/// ViewModel
/// </summary>
public TViewModel ViewModel
{
get
{
return (TViewModel)DataContext;
}
private set
{
DataContext = value;
}
}
}
}
my xaml file
<mvvm:ViewBase x:Class="CustomCopyNas.Controls.FolderControl"
x:TypeArguments="vm:FolderViewModel"
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:mvvm="clr-namespace:CustomCopyNas.MVVM"
xmlns:vm="clr-namespace:CustomCopyNas.Views"
xmlns:enum="clr-namespace:CustomCopyNas.Enum"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Width="700">
<mvvm:ViewBase.Resources>
<ObjectDataProvider x:Key="osEnum" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type Type="enum:OsType"></x:Type>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</mvvm:ViewBase.Resources>
<Grid>
<DataGrid ItemsSource="{Binding Folders, Mode=TwoWay}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Folder or File" Binding="{Binding Path}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</mvvm:ViewBase>
and partial class
using CustomCopyNas.MVVM;
using CustomCopyNas.Views;
namespace CustomCopyNas.Controls
{
/// <summary>
/// Interaction logic for FolderControl.xaml
/// </summary>
public partial class FolderControl : ViewBase<FolderViewModel>
{
public FolderControl()
: base(new FolderViewModel("SourceFolders.xml"))
{
InitializeComponent();
}
}
}
When i am trying to compile, i've got error, that the property resources does not exist on viewbase. I counld not figure out, where the error is and my viewbase class is inherited from usercontrol class, this provide resources property.
What is here wrong?
I believe that your problems are caused because generic classes are not supported in XAML. You can read the full story in the Generics in XAML page on MSDN, but in short, from the linked page:
In XAML, a generic type must always be represented as a constrained generic; an unconstrained generic is never present in the XAML type system or a XAML node stream and cannot be represented in XAML markup.
As such, you have a mismatch between your code class declaration:
public class ViewBase<TViewModel>
And your XAML class declaration:
<mvvm:ViewBase x:Class="CustomCopyNas.Controls.FolderControl"
The fact that they do not match will cause you a variety of problems.
Please see the Can I specify a generic type in XAML? and WPF UserControl with generic code-behind questions for further information on this subject.
Related
I am starting with WPF and I have this problem. I have a file called MainWindow.xaml with this code:
<Window x:Class="View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:View" xmlns:system="clr-namespace:System;assembly=System.Runtime"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid >
<ItemsControl ItemsSource="{Binding}" x:Name="boardView">
</ItemsControl>
</Grid>
</Window>
And I have another file called MainWindow.xaml.cs with this code
namespace ViewModel
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var items = new List<string> { "a", "b", "c", "d", "e" };
}
}
}
Now I have to assign this list to boardView.ItemsSource. How can I do that?
You have four problems here that I can see that would need to get fixed for this to work.
In order for data binding to work, you need to set the DataContext of your MainWindow.
MainWindow.xaml.cs:
// Put this in the constructor after InitializeComponents();
this.DataContext = this;
Another requirement for data binding is to implement the INotifyPropertyChanged interface on the class you wish to having data binding (in your case this is MainWindow, but I recommend you read on MVVM design):
MainWindow.xaml.cs:
public partial class MainWindow : Window, INotifyPropertyChanged
Data bindings only work on public properties, so using var items isn't following this requirement. Instead, make var items a public property that updates itself with the PropertyChanged event whenever the value changes.
MainWindow.xaml.cs:
private List<string> items;
public List<string> Items
{
get => this.items;
set
{
this.items = value;
PropertyChanged?.Invoke(this, new PropertyName(nameof(Items)));
}
}
Lastly, you need to fix your binding in the xaml to bind to your public property.
MainWindow.xaml:
<ItemsControl ItemsSource="{Binding Items}" x:Name="boardView">
A have read a lot of method about the ways of binding enum to combobox. So now in .Net 4.5 it should be pretty ease. But my code dont work.
Dont really understand why.
xaml:
<Window x:Class="SmartTrader.Windows.SyncOfflineDataWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SyncOfflineDataWindow" Height="300" Width="300">
<Grid>
<StackPanel>
<ComboBox ItemsSource="{Binding StrategyTypes}" SelectedItem="{Binding StrategyType}" />
<Button Width="150" Margin="5" Padding="5" Click="Button_Click">Save</Button>
</StackPanel>
</Grid>
xaml.cs backend
namespace SmartTrader.Windows
{
/// <summary>
/// Interaction logic for SyncOfflineDataWindow.xaml
/// </summary>
public partial class SyncOfflineDataWindow : Window
{
public SyncOfflineDataWindow(IPosition position, ContractType type)
{
DataContext = new ObservablePosition(position);
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
}
}
View Model:
namespace SmartTrader.Entity
{
public class ObservablePosition : NotifyPropertyChanged, IPosition
{
public IEnumerable<StrategyType> StrategyTypes =
Enum.GetValues(typeof (StrategyType)).Cast<StrategyType>();
public ObservablePosition(IPosition position)
{
Strategy = position.Strategy;
}
private StrategyType _strategyType = StrategyType.None;
public StrategyType Strategy
{
get { return _strategyType; }
set
{
_strategyType = value;
OnPropertyChanged();
}
}
}
}
StrategyType is enum.
All i have got it is empty dropdown list
You are trying to bind to a private variable, instead, your enum should be exposed as a Property.
public IEnumerable<StrategyTypes> StrategyTypes
{
get
{
return Enum.GetValues(typeof(StrategyType)).Cast<StrategyType>();
}
}
Also, Discosultan has already solved another problem for you.
Simplest way to bind any enum data to combobox in wpf XAML:
Add data provider in window or user control resource
xmlns:pro="clr-namespace:TestProject">
<UserControl.Resources>
<ObjectDataProvider x:Key="getDataFromEnum" MethodName="GetValues" ObjectType="{x:Type System:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="pro:YourEnumName"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</UserControl.Resources>
<!--ComboBox xaml:-->
<ComboBox ItemsSource="{Binding Source={StaticResource getDataFromEnum}}"/>
I have found a solution on youtube. Check the link below:
How to Bind an Enum to a ComboBox in WPF: https://youtu.be/Bp5LFXjwtQ0
This solution creates a new class derived from MarkupExtension class and uses this class as a source in the XAML code.
EnumBindingSourceExtention.cs file:
namespace YourProject.Helper
{
public class EnumBindingSourceExtention : MarkupExtension
{
public Type EnumType { get; private set; }
public EnumBindingSourceExtention(Type enumType)
{
if (enumType == null || !enumType.IsEnum)
{
throw new Exception("EnumType is null or not EnumType");
}
this.EnumType = enumType;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return Enum.GetValues(EnumType);
}
}
}
View.Xaml file:
<Window
xmlns:helper="clr-namespace:YourProject.Helper"/>
<ComboBox
ItemsSource="{Binding Source={helper:EnumBindingSourceExtention {x:Type local:TheEnumClass}}}" />
local:TheEnumClass: TheEumClass should be located where you specify the namespace (in this case, it is on local)
I have a MainWindow that contains multiple views using MVVM. In fact the MainWindow holds only a list of Models and each time a Model is added it creates a View (here a UserControl) and associates the DataContext (Model) to the View. Each view is put into a separate TabItem in a TabControl.
The Model itself has a CommandBindingsCollection and assigns this command bindings to the View. This means that for example F10 is available multiple times, but should only the active View should react on F10.
But, F10 does not work at all. Only if I assign the CommandBinding to the MainWindow it works, but this makes the View dependent on the UserControl and this is not what I want, since I wnat to create the View as independent as possible from the MainWindow.
The only solution I have is to make this dynamically intercepting the change of the current TabItem and add/remove the commands for the active View. Currently everything works without code, but then I have to write code for it.
Attached is a code of the MainWindow:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication3"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
</Window>
using System.Windows;
namespace WpfApplication3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
PluginControl aControl = new PluginControl();
Content = aControl;
}
}
}
and the code of the UserControl:
<UserControl x:Class="WpfApplication3.PluginControl"
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:WpfApplication3"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Background="White">
<StackPanel>
<Button Command="{Binding myCommand}" Content="PushMe" Focusable="False"/>
<Label Content="Nothing pressed" Name="myLabel"/>
</StackPanel>
</UserControl>
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApplication3
{
/// <summary>
/// Interaction logic for PluginControl.xaml
/// </summary>
public partial class PluginControl : UserControl
{
public RoutedCommand myCommand
{
get;
private set;
}
public PluginControl()
{
InitializeComponent();
DataContext = this;
myCommand = new RoutedCommand();
myCommand.InputGestures.Add(new KeyGesture(Key.F10));
CommandBindings.Add(new CommandBinding(myCommand, myCommandHandler));
}
private void myCommandHandler(object sender, ExecutedRoutedEventArgs executed)
{
myLabel.Content = DateTime.Now.ToString();
}
}
}
As you see I have set the Button to Focusable false, since I want to have the command working in general, not only when the button is focused. I'm I missing something or thinking in a wrong direction, that making adding a CommandBinding does not implicitly mean that the command does work without binding it?
Adding the Command to the MainWindow itself works.
Any help?
I have read through a few articles on this and I can't see what im doing wrong here could anyone help :)
I have a UserControl called CreateRuleItemView I want to add a Dependency Property on here that I can bind my ViewModel too. So far I have.
public partial class CreateRuleItemView : UserControl
{
public CreateRuleItemView()
{
InitializeComponent();
}
public Boolean ShowEditTablePopup
{
get
{
return (Boolean)this.GetValue(ShowEditTablePopupProperty);
}
set
{
this.SetValue(ShowEditTablePopupProperty, value);
}
}
public static readonly DependencyProperty ShowEditTablePopupProperty = DependencyProperty.Register("ShowEditTablePopup", typeof(Boolean), typeof(CreateRuleItemView), new PropertyMetadata(null, OnShowEditTablePopupChanged));
private static void OnShowEditTablePopupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
}
}
If I then try to access the property in the User Control Xaml I get:
<UserControl x:Class="Views.Setup.CreateRuleItemView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DataContext="{d:DesignInstance Type=vm:CreateRuleItemViewModel, IsDesignTimeCreatable=False}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" ShowEditTablePopup="{Binding DataContext.ShowEditTablePopup}" >
Error 1 The member "ShowEditTablePopup" is not recognized or is not accessible.
Error 3 The property 'ShowEditTablePopup' does not exist on the type 'UserControl'
Error 2 The property 'ShowEditTablePopup' was not found in type 'UserControl'.
Edit 1:
Ok Managed to get around this by adding the binding in the code behind on my Main window where i setup my view.
Setup.CreateRuleItemView v = new Setup.CreateRuleItemView();
BindingOperations.SetBinding(v, CreateRuleItemView.EditTablePopupProperty, new Binding("EditTablePopup"));
You won't be able to achieve this with a UserControl (I've just tried replacing the <UserControl... partial declaration in XAML with <local:CreateRuleItemView when recreating the code locally, but this results in a circular reference and thus won't compile/will potentially result in a XamlParseException). I'd write a control inheriting from ContentControl to which you can add the property and template it instead (I did this with WPF so the namespaces may differ, otherwise the code will work):
using System;
using System.Windows;
using System.Windows.Controls;
namespace DepPropTest
{
/// <summary>
/// Description of CreateRuleItemView.
/// </summary>
public class CreateRuleItemView : ContentControl
{
public CreateRuleItemView()
{
}
public static readonly DependencyProperty ShowEditTablePopupProperty =
DependencyProperty.Register("ShowEditTablePopup", typeof (bool), typeof (CreateRuleItemView), new PropertyMetadata());
public bool ShowEditTablePopup
{
get { return (bool) GetValue(ShowEditTablePopupProperty); }
set { SetValue(ShowEditTablePopupProperty, value); }
}
}
}
Then you can use it as follows (this example uses WPF by the way, hence Window being the parent control):
<Window x:Class="DepPropTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DepPropTest"
Title="DepPropTest" Height="300" Width="300">
<local:CreateRuleItemView Width="300"
Height="300"
ShowEditTablePopup="True">
<local:CreateRuleItemView.Template>
<ControlTemplate>
<!-- define your control's visual appearance... -->
</ControlTemplate>
</local:CreateRuleItemView.Template>
<TextBox Text="Some content for your view" />
</local:CreateRuleItemView>
</Window>
I have a class defined as:
class Constants
{
public static string settingsToolTip = "Settings";
}
I want to set this string for a tooltip of a button like:
<Button Name= "ButtonSettingsWindow" ToolTip="Settings" ToolTipService.ShowDuration="2000"/>
Instead of hardcoding the string "Settings" in XAML, I want it to use the string from Constants class. How can i do this in WPF XAML?
You can access static members of class using x:Static markup extension in XAML.
<Button ToolTip="{x:Static local:Constants.settingsToolTip}"/>
Make sure you have added namespace in XAML file (local) where Constant class is declared:
xmlns:local="clr-namespace:ActualNameSpace"
The answer you're looking for is binding.
Example:
Code behind:
class Test
{
public string test { get { return "Settings"; } }
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
XAML:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:y="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<y:Test></y:Test>
</Window.DataContext>
<Grid>
<Button Content="{Binding test}"></Button>
</Grid>
The result is a button that says "Settings" :)