用户控件的Viewmodel? [英] Viewmodel for usercontrol?

查看:96
本文介绍了用户控件的Viewmodel?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个WPF应用程序,我试图创建一个屏幕键盘作为Usercontrol。



这是设计的XAML:



I have a WPF app where I am trying to create an on-screen keyboard as a Usercontrol.

Here is the XAML for the design:

<UserControl x:Class="MyDiskTools.UserControls.NodeGrid.NodeGrid"

             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:MyDiskTools.UserControls.NodeGrid"

             mc:Ignorable="d">
    <Grid>
        <Grid.Resources>
            <Style TargetType="Button">
                <Setter Property="Padding" Value="{Binding ButtonPadding, FallbackValue=5}"/>
                <Setter Property="BorderThickness" Value="{Binding ButtonBorderThickness, FallbackValue=1}"/>
                <Setter Property="Command" Value="{Binding InputCharacterCommand}"/>
                <Setter Property="CommandParameter" Value="{Binding Path=Content, RelativeSource={RelativeSource Self}}"/>
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="BorderThickness" Value="{Binding HighlightBorderThickness, FallbackValue=5}"/>
                        <Setter Property="FontSize" Value="{Binding HighlightFontSize, FallbackValue=20}"/>                        
                    </Trigger>
                </Style.Triggers>
            </Style>            
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <UniformGrid Grid.Row="0" Rows="1">
            <Button Content="A" />
            <Button Content="B" />
            <Button Content="C" />
            <Button Content="D" />
            <Button Content="E" />
            <Button Content="F" />
        </UniformGrid>
        <UniformGrid Grid.Row="1" Rows="1">
            <Button Content="G" />
            <Button Content="H" />
            <Button Content="I" />
            <Button Content="J" />
            <Button Content="K" />
            <Button Content="L" />
            <Button Content="M" />
        </UniformGrid>
        <UniformGrid Grid.Row="2" Rows="1">
            <Button Content="N" />
            <Button Content="O" />
            <Button Content="P" />
            <Button Content="Q" />
            <Button Content="R" />
            <Button Content="S" />
            <Button Content="T" />
        </UniformGrid>
        <UniformGrid Grid.Row="3" Rows="1">
            <Button Content="U" />
            <Button Content="V" />
            <Button Content="W" />
            <Button Content="X" />
            <Button Content="Y" />
            <Button Content="Z" />
        </UniformGrid>
        <TextBox Name="InputMessage"  IsEnabled="False" Background="Beige" Grid.Row="4" Text="{Binding PasswordDisplay, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</UserControl>





代码隐藏在这里:





The code-behind is here:

public partial class NodeGrid : UserControl
    {
        public NodeGrid()
        {
            InitializeComponent();
            DataContext = new NodeGridVM();
        }

        public string Message
        {
            get
            {
                return InputMessage.Text;
            }
        }

        #region Dependency Properties
        [TypeConverter(typeof(LengthConverter))]

        
        public double InternalPadding
        {
            get { return (double)GetValue(InternalPaddingProperty); }
            set { SetValue(InternalPaddingProperty, value); }
        }

        // Using a DependencyProperty as the backing store for InternalPadding.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InternalPaddingProperty =
            DependencyProperty.Register("InternalPadding", typeof(double), typeof(NodeGrid), new PropertyMetadata(double.NaN));

        public double ButtonHeight
        {
            get { return (double)GetValue(ButtonHeightProperty); }
            set { SetValue(ButtonHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ButtonHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ButtonHeightProperty =
            DependencyProperty.Register("ButtonHeight", typeof(double), typeof(NodeGrid), new PropertyMetadata(double.NaN));
        #endregion
    }





...和ViewModel是:





... and the ViewModel is:

class NodeGridVM : INotifyPropertyChanged
    {
        private string _passwordDisplay = "";

        public string PasswordDisplay
        {
            get
            {
                return _passwordDisplay;
            }

            set
            {
                if (value != _passwordDisplay)
                {
                    _passwordDisplay = value;
                    OnPropertyChange();
                }
            }
        }

        private ICommand _inputCharacterCommand;

        public ICommand InputCharacterCommand
        {
            get
            {
                if (_inputCharacterCommand == null)
                {
                    InputCharacterCommand = new InputCharacterCommand(this);
                }
                    
                return _inputCharacterCommand;
            }

            set
            {
                _inputCharacterCommand = value;
            }
        }
        public void AddCharacter(string input)
        {
            if (input != null)
            {
                PasswordDisplay = String.Concat(PasswordDisplay, input);
            }            
        }

        private void OnPropertyChange([CallerMemberName] string property = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public bool InputAllowed()
        {
            if (PasswordDisplay == null)
            {
                return true;
            }

            if (PasswordDisplay.Length > 20)
            {
                return false;
            }

            return true;
        }
    }

    class InputCharacterCommand : ICommand
    {
        private NodeGridVM _viewmodel;

        public InputCharacterCommand(NodeGridVM vm)
        {
            _viewmodel = vm;
        }

        public event EventHandler CanExecuteChanged;
        

        public bool CanExecute(object parameter)
        {
            return (_viewmodel.InputAllowed());
        }

        public void Execute(object parameter)
        {
            _viewmodel.AddCharacter(parameter as String);
        }
    }





Please do note that this is just a sketch-up of the code, and more dependency properties will be created for future use.



What I have tried:



However, according to most of the opinions online, giving a Usercontrol a viewmodel of its own is an extremely bad idea. Should I, then, scrap the ViewModel and just put all the logic in the code-behind file?



Please do note that this is just a sketch-up of the code, and more dependency properties will be created for future use.

What I have tried:

However, according to most of the opinions online, giving a Usercontrol a viewmodel of its own is an extremely bad idea. Should I, then, scrap the ViewModel and just put all the logic in the code-behind file?

推荐答案

Quote:

according to most of the opinions online, giving a Usercontrol a viewmodel of its own is an extremely bad idea

according to most of the opinions online, giving a Usercontrol a viewmodel of its own is an extremely bad idea

This is a new one for me. Popular opinion is actually the complete opposite! To me, it is personal preference or usage-specific.



For example, I may have a complex entry form with a lot of Xaml. The form has the VM (ViewModel), but regions of the form are broken out into separate UCs (UserControls).



Another example code be that each region on a form has a specific task, so the form is just a container with no VM, and each region has its own function, so there are multiple UCs each with their own VMs.



The easiest framework rule to remember is UI code belongs in the code-behind, logic in the VM.



An on-screen keyboard is something that is re-usable. So it should be code so that it can be used in any input control: eg: any TextBox on a window/control.



Hope this helps!

This is a new one for me. Popular opinion is actually the complete opposite! To me, it is personal preference or usage-specific.

For example, I may have a complex entry form with a lot of Xaml. The form has the VM (ViewModel), but regions of the form are broken out into separate UCs (UserControls).

Another example code be that each region on a form has a specific task, so the form is just a container with no VM, and each region has its own function, so there are multiple UCs each with their own VMs.

The easiest framework rule to remember is UI code belongs in the code-behind, logic in the VM.

An on-screen keyboard is something that is re-usable. So it should be code so that it can be used in any input control: eg: any TextBox on a window/control.

Hope this helps!


这篇关于用户控件的Viewmodel?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆