admin管理员组文章数量:1026373
In a WinUI3 project, I have 3 views IconEditorView
, ColorEditorView
, and ImageEditorView
, each with their corresponding ViewModel IconEditorViewModel
, ColorEditorViewModel
, and ImageEditorViewModel
. The views are practically the same, the only differences are a few labels that are binded from the ViewModel anyways (the specific UI elements are in independent UserControls within the views).
I was wondering if there is any way to be able to have a generic view like EditorView
and attach the corresponding ViewModel. Since they all implement IEditorViewModel
they all have everything that would be necessary for EditorView
to work. Currently, for each view, I attach the corresponding ViewModel by using a dependency property like so:
public sealed partial class ImageEditorView : UserControl
{
public ImageEditorViewModel ImageEditorViewModel
{
get => (ImageEditorViewModel)GetValue(ImageEditorViewModelProperty);
set => SetValue(ImageEditorViewModelProperty, value);
}
public static readonly DependencyProperty ImageEditorViewModelProperty =
DependencyProperty.Register(
nameof(ImageEditorViewModel),
typeof(ImageEditorViewModel),
typeof(ImageEditorView),
new PropertyMetadata(default));
public ImageEditorView(ImageEditorViewModel imageEditorViewModel)
{
this.InitializeComponent();
ImageEditorViewModel = imageEditorViewModel;
}
}
Silly me tried converting the ViewModel property type to an IEditorViewModel
, but that, of course, did not work since I needed data binding for updating a few workflow indicators as the user interacts with the view.
In the future, I will likely add new editors, so this approach would be very convenient to just create the ViewModel implementing IEditorViewModel
and attach it to an instance of the existing generic EditorView
.
How can I achieve this?
Note: I'm using WinUI3 latest stable version along with CommunityToolkit.MVVM if that's relevant in any way.
Thanks!
In a WinUI3 project, I have 3 views IconEditorView
, ColorEditorView
, and ImageEditorView
, each with their corresponding ViewModel IconEditorViewModel
, ColorEditorViewModel
, and ImageEditorViewModel
. The views are practically the same, the only differences are a few labels that are binded from the ViewModel anyways (the specific UI elements are in independent UserControls within the views).
I was wondering if there is any way to be able to have a generic view like EditorView
and attach the corresponding ViewModel. Since they all implement IEditorViewModel
they all have everything that would be necessary for EditorView
to work. Currently, for each view, I attach the corresponding ViewModel by using a dependency property like so:
public sealed partial class ImageEditorView : UserControl
{
public ImageEditorViewModel ImageEditorViewModel
{
get => (ImageEditorViewModel)GetValue(ImageEditorViewModelProperty);
set => SetValue(ImageEditorViewModelProperty, value);
}
public static readonly DependencyProperty ImageEditorViewModelProperty =
DependencyProperty.Register(
nameof(ImageEditorViewModel),
typeof(ImageEditorViewModel),
typeof(ImageEditorView),
new PropertyMetadata(default));
public ImageEditorView(ImageEditorViewModel imageEditorViewModel)
{
this.InitializeComponent();
ImageEditorViewModel = imageEditorViewModel;
}
}
Silly me tried converting the ViewModel property type to an IEditorViewModel
, but that, of course, did not work since I needed data binding for updating a few workflow indicators as the user interacts with the view.
In the future, I will likely add new editors, so this approach would be very convenient to just create the ViewModel implementing IEditorViewModel
and attach it to an instance of the existing generic EditorView
.
How can I achieve this?
Note: I'm using WinUI3 latest stable version along with CommunityToolkit.MVVM if that's relevant in any way.
Thanks!
Share Improve this question edited Nov 18, 2024 at 2:58 Hector Lazarin asked Nov 16, 2024 at 20:20 Hector LazarinHector Lazarin 826 bronze badges 3 |1 Answer
Reset to default 1You could use DataTemplateSelector for this.
Let's say we have these editor classes:
public interface IEditor
{
string Name { get; }
}
public class IconEditor : IEditor
{
public string Name { get; } = nameof(IconEditor);
public Symbol Icon { get; set; }
}
public class ColorEditor : IEditor
{
public string Name { get; } = nameof(ColorEditor);
public Brush Color { get; set; } = new SolidColorBrush(Colors.Transparent);
}
then the custom control could be:
EditorView.cs
public class EditorView : Control
{
public static readonly DependencyProperty EditorProperty =
DependencyProperty.Register(nameof(Editor),
typeof(IEditor),
typeof(EditorView),
new PropertyMetadata(default));
public static readonly DependencyProperty EditorTemplateSelectorProperty =
DependencyProperty.Register(
nameof(EditorTemplateSelector),
typeof(DataTemplateSelector),
typeof(EditorView),
new PropertyMetadata(default));
public EditorView()
{
DefaultStyleKey = typeof(EditorView);
}
public ContentPresenter? EditorPresenter { get; set; }
public IEditor Editor
{
get => (IEditor)GetValue(EditorProperty);
set => SetValue(EditorProperty, value);
}
public DataTemplateSelector EditorTemplateSelector
{
get => (DataTemplateSelector)GetValue(EditorTemplateSelectorProperty);
set => SetValue(EditorTemplateSelectorProperty, value);
}
}
Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft/winfx/2006/xaml"
xmlns:local="using:App1">
<Style TargetType="local:EditorView">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:EditorView">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentControl
Content="{TemplateBinding Editor}"
ContentTemplateSelector="{TemplateBinding EditorTemplateSelector}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
and the DataTemplateSelector
could be something like this:
DataTemplateSelector with Dictionary in XAML
public class StringToDataTemplateDictionary : Dictionary<string, DataTemplate>
{
}
public class EditorTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultTemplate { get; set; } = new();
public StringToDataTemplateDictionary DataTemplates { get; set; } = [];
protected override DataTemplate SelectTemplateCore(object item)
{
return base.SelectTemplateCore(item);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return item is IEditor editor
? DataTemplates.TryGetValue(editor.Name, out var template) is true
? template
: DefaultTemplate
: DefaultTemplate;
}
}
finally, we can use the control:
<Page.Resources>
<local:EditorTemplateSelector x:Key="EditorTemplateSelector">
<local:EditorTemplateSelector.DataTemplates>
<DataTemplate
x:Key="IconEditor"
x:DataType="local:IconEditor">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind Name}" />
<SymbolIcon Symbol="{x:Bind Icon}" />
</StackPanel>
</DataTemplate>
<DataTemplate
x:Key="ColorEditor"
x:DataType="local:ColorEditor">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind Name}" />
<Rectangle
Width="32"
Height="32"
Fill="{x:Bind Color}" />
</StackPanel>
</DataTemplate>
</local:EditorTemplateSelector.DataTemplates>
</local:EditorTemplateSelector>
</Page.Resources>
<StackPanel>
<Button
Click="ToggleEditorButton_Click"
Content="Toggle Editor" />
<local:EditorView
x:Name="EditorViewControl"
EditorTemplateSelector="{StaticResource EditorTemplateSelector}" />
</StackPanel>
private void ToggleEditorButton_Click(object sender, RoutedEventArgs e)
{
EditorViewControl.Editor = EditorViewControl.Editor is IconEditor
? new ColorEditor() { Color = new SolidColorBrush(Colors.SkyBlue) }
: new IconEditor() { Icon = Symbol.Home };
}
In a WinUI3 project, I have 3 views IconEditorView
, ColorEditorView
, and ImageEditorView
, each with their corresponding ViewModel IconEditorViewModel
, ColorEditorViewModel
, and ImageEditorViewModel
. The views are practically the same, the only differences are a few labels that are binded from the ViewModel anyways (the specific UI elements are in independent UserControls within the views).
I was wondering if there is any way to be able to have a generic view like EditorView
and attach the corresponding ViewModel. Since they all implement IEditorViewModel
they all have everything that would be necessary for EditorView
to work. Currently, for each view, I attach the corresponding ViewModel by using a dependency property like so:
public sealed partial class ImageEditorView : UserControl
{
public ImageEditorViewModel ImageEditorViewModel
{
get => (ImageEditorViewModel)GetValue(ImageEditorViewModelProperty);
set => SetValue(ImageEditorViewModelProperty, value);
}
public static readonly DependencyProperty ImageEditorViewModelProperty =
DependencyProperty.Register(
nameof(ImageEditorViewModel),
typeof(ImageEditorViewModel),
typeof(ImageEditorView),
new PropertyMetadata(default));
public ImageEditorView(ImageEditorViewModel imageEditorViewModel)
{
this.InitializeComponent();
ImageEditorViewModel = imageEditorViewModel;
}
}
Silly me tried converting the ViewModel property type to an IEditorViewModel
, but that, of course, did not work since I needed data binding for updating a few workflow indicators as the user interacts with the view.
In the future, I will likely add new editors, so this approach would be very convenient to just create the ViewModel implementing IEditorViewModel
and attach it to an instance of the existing generic EditorView
.
How can I achieve this?
Note: I'm using WinUI3 latest stable version along with CommunityToolkit.MVVM if that's relevant in any way.
Thanks!
In a WinUI3 project, I have 3 views IconEditorView
, ColorEditorView
, and ImageEditorView
, each with their corresponding ViewModel IconEditorViewModel
, ColorEditorViewModel
, and ImageEditorViewModel
. The views are practically the same, the only differences are a few labels that are binded from the ViewModel anyways (the specific UI elements are in independent UserControls within the views).
I was wondering if there is any way to be able to have a generic view like EditorView
and attach the corresponding ViewModel. Since they all implement IEditorViewModel
they all have everything that would be necessary for EditorView
to work. Currently, for each view, I attach the corresponding ViewModel by using a dependency property like so:
public sealed partial class ImageEditorView : UserControl
{
public ImageEditorViewModel ImageEditorViewModel
{
get => (ImageEditorViewModel)GetValue(ImageEditorViewModelProperty);
set => SetValue(ImageEditorViewModelProperty, value);
}
public static readonly DependencyProperty ImageEditorViewModelProperty =
DependencyProperty.Register(
nameof(ImageEditorViewModel),
typeof(ImageEditorViewModel),
typeof(ImageEditorView),
new PropertyMetadata(default));
public ImageEditorView(ImageEditorViewModel imageEditorViewModel)
{
this.InitializeComponent();
ImageEditorViewModel = imageEditorViewModel;
}
}
Silly me tried converting the ViewModel property type to an IEditorViewModel
, but that, of course, did not work since I needed data binding for updating a few workflow indicators as the user interacts with the view.
In the future, I will likely add new editors, so this approach would be very convenient to just create the ViewModel implementing IEditorViewModel
and attach it to an instance of the existing generic EditorView
.
How can I achieve this?
Note: I'm using WinUI3 latest stable version along with CommunityToolkit.MVVM if that's relevant in any way.
Thanks!
Share Improve this question edited Nov 18, 2024 at 2:58 Hector Lazarin asked Nov 16, 2024 at 20:20 Hector LazarinHector Lazarin 826 bronze badges 3- For a "view" that changes based on what's in the the (view) "model", I use properties such as "IsVisible" to reflect a particlular aspect of the current "context". They're simply "getters" that say a particluar element should be visible or not visible (or the FontSize is different; etc.); based on some other properties. (e.g. Infantry vs cavalry vs artillery). – Gerry Schmitz Commented Nov 17, 2024 at 19:05
-
You could use something like
(model is IEditImage)
to show / hide parts of the view. Or just define an abstract base type for the common bits. – Jeremy Lakeman Commented Nov 18, 2024 at 3:22 - You could try to create a wrapper view model that contains references to the different view models you want to use. I suggest you could refer to the thread: learn.microsoft/en-us/answers/questions/1151482/… – Jeaninez - MSFT Commented Nov 18, 2024 at 6:02
1 Answer
Reset to default 1You could use DataTemplateSelector for this.
Let's say we have these editor classes:
public interface IEditor
{
string Name { get; }
}
public class IconEditor : IEditor
{
public string Name { get; } = nameof(IconEditor);
public Symbol Icon { get; set; }
}
public class ColorEditor : IEditor
{
public string Name { get; } = nameof(ColorEditor);
public Brush Color { get; set; } = new SolidColorBrush(Colors.Transparent);
}
then the custom control could be:
EditorView.cs
public class EditorView : Control
{
public static readonly DependencyProperty EditorProperty =
DependencyProperty.Register(nameof(Editor),
typeof(IEditor),
typeof(EditorView),
new PropertyMetadata(default));
public static readonly DependencyProperty EditorTemplateSelectorProperty =
DependencyProperty.Register(
nameof(EditorTemplateSelector),
typeof(DataTemplateSelector),
typeof(EditorView),
new PropertyMetadata(default));
public EditorView()
{
DefaultStyleKey = typeof(EditorView);
}
public ContentPresenter? EditorPresenter { get; set; }
public IEditor Editor
{
get => (IEditor)GetValue(EditorProperty);
set => SetValue(EditorProperty, value);
}
public DataTemplateSelector EditorTemplateSelector
{
get => (DataTemplateSelector)GetValue(EditorTemplateSelectorProperty);
set => SetValue(EditorTemplateSelectorProperty, value);
}
}
Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft/winfx/2006/xaml"
xmlns:local="using:App1">
<Style TargetType="local:EditorView">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:EditorView">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentControl
Content="{TemplateBinding Editor}"
ContentTemplateSelector="{TemplateBinding EditorTemplateSelector}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
and the DataTemplateSelector
could be something like this:
DataTemplateSelector with Dictionary in XAML
public class StringToDataTemplateDictionary : Dictionary<string, DataTemplate>
{
}
public class EditorTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultTemplate { get; set; } = new();
public StringToDataTemplateDictionary DataTemplates { get; set; } = [];
protected override DataTemplate SelectTemplateCore(object item)
{
return base.SelectTemplateCore(item);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return item is IEditor editor
? DataTemplates.TryGetValue(editor.Name, out var template) is true
? template
: DefaultTemplate
: DefaultTemplate;
}
}
finally, we can use the control:
<Page.Resources>
<local:EditorTemplateSelector x:Key="EditorTemplateSelector">
<local:EditorTemplateSelector.DataTemplates>
<DataTemplate
x:Key="IconEditor"
x:DataType="local:IconEditor">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind Name}" />
<SymbolIcon Symbol="{x:Bind Icon}" />
</StackPanel>
</DataTemplate>
<DataTemplate
x:Key="ColorEditor"
x:DataType="local:ColorEditor">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind Name}" />
<Rectangle
Width="32"
Height="32"
Fill="{x:Bind Color}" />
</StackPanel>
</DataTemplate>
</local:EditorTemplateSelector.DataTemplates>
</local:EditorTemplateSelector>
</Page.Resources>
<StackPanel>
<Button
Click="ToggleEditorButton_Click"
Content="Toggle Editor" />
<local:EditorView
x:Name="EditorViewControl"
EditorTemplateSelector="{StaticResource EditorTemplateSelector}" />
</StackPanel>
private void ToggleEditorButton_Click(object sender, RoutedEventArgs e)
{
EditorViewControl.Editor = EditorViewControl.Editor is IconEditor
? new ColorEditor() { Color = new SolidColorBrush(Colors.SkyBlue) }
: new IconEditor() { Icon = Symbol.Home };
}
本文标签: cUsing the same view for different ViewModels in WinUI3Stack Overflow
版权声明:本文标题:c# - Using the same view for different ViewModels in WinUI3 - Stack Overflow 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://it.en369.cn/questions/1745644216a2160928.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
(model is IEditImage)
to show / hide parts of the view. Or just define an abstract base type for the common bits. – Jeremy Lakeman Commented Nov 18, 2024 at 3:22