草庐IT

在ViewModel中访问USERCONTROL

程序员大本营 2024-04-19 原文

视图:我有usercontrol,它具有文本框和标签。当“ Enter”键关闭时,我希望标签使用文本框的值表单更新。为了这个示例,我创建了一个CaruserControl。我将在MainWindow的ItemScontrol中托管这些列表。

模型:我有班车,这将是模型。

ViewModel:我没有Carusercontrol和汽车的ViewModel。我为MainWindow提供了一个 - 我们将其称为MainViewModel。

我可以从各个usercontrols到MainViewModel传播命令,但是我不确定从MainViewModel中的文本框中获取值吗?

以下是我从我在线阅读的有关MVVM的内容中做出的一些假设(当然有一些来源说假设是错误的)。

1] USERCONTROL不应具有ViewModel。

2] USERCONTROL只能揭示依赖性属性,而不应具有InotifyChanged或事件的公共属性。

因此,问题是,如何更新标签,并在MainViewModel中访问文本框值。

这是测试代码:

----- carusercontrol.xaml ----

<UserControl x:Class="TestMVVM.CarUserControl"             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:TestMVVM"             mc:Ignorable="d"              d:DesignHeight="50" d:DesignWidth="300" x:Name="thisUC">    <Grid>        <Grid.ColumnDefinitions>            <ColumnDefinition Width="*"/>            <ColumnDefinition Width="*"/>        </Grid.ColumnDefinitions>        <Label Grid.Column="0">--</Label>        <TextBox Grid.Column="1" Background="#FFE8D3D3" BorderThickness="0">            <TextBox.InputBindings>                <KeyBinding Key="Enter"                                 Command="{Binding KeyDownCommand, ElementName=thisUC}"                                 CommandParameter="{Binding}"/>            </TextBox.InputBindings>        </TextBox>    </Grid></UserControl>

----- carusercontrol.cs -----------------

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Navigation;using System.Windows.Shapes;namespace TestMVVM{    /// <summary>    /// Interaction logic for CarUserControl.xaml    /// The Usercontrol    /// </summary>    public partial class CarUserControl : UserControl    {        private static readonly DependencyProperty StrValueProperty = DependencyProperty.Register("StrValue", typeof(float), typeof(CarUserControl), new PropertyMetadata(null));        private static readonly DependencyProperty KeyDownCommandProperty = DependencyProperty.Register("KeyDownCommand", typeof(ICommand), typeof(CarUserControl), new PropertyMetadata(null)); //Enter key down in the text box        public CarUserControl()        {            InitializeComponent();        }        public string StrValue        {            get { return (string)GetValue(StrValueProperty); }            set { SetValue(StrValueProperty, value); }        }        /// <summary>        /// "Enter" key down        /// </summary>        public ICommand KeyDownCommand        {            get { return (ICommand)GetValue(KeyDownCommandProperty); }            set { SetValue(KeyDownCommandProperty, value); }        }    }}

// ---型号 - car.cs

using System;using System.Collections.Generic;using System.ComponentModel;using System.Linq;using System.Text;using System.Threading.Tasks;namespace TestMVVM{    /// <summary>    /// A simple model    /// </summary>    class Car : INotifyPropertyChanged    {        public Car(string name) {            this.name = name;        }        private string name;        public event PropertyChangedEventHandler PropertyChanged;        public string Name        {            get { return name; }            set            {                name = value;                OnPropertyChanged("Name");            }        }        public void OnPropertyChanged(string name)        {            PropertyChangedEventHandler handler = PropertyChanged;            if (handler != null)            {                handler(this, new PropertyChangedEventArgs(name));            }        }    }}

-----主视图模型---

using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.ComponentModel;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Input;namespace TestMVVM{    /// <summary>    /// The Main View Model    /// </summary>    class MainViewModel : INotifyPropertyChanged    {        /// <summary>        /// The main view model        /// </summary>        public MainViewModel()        {            //Create some test data            cars = new ObservableCollection<Car>();            cars.Add(new Car("Audi"));            cars.Add(new Car("Toyota"));            cars.Add(new Car("Subaru"));            cars.Add(new Car("Volvo"));        }        public event PropertyChangedEventHandler PropertyChanged;        private ObservableCollection<Car> cars; //List of tensioner spools        private ICommand enterDownCommand;        public ObservableCollection<Car> Cars        {            get { return cars; }            set            {                cars = value;                OnPropertyChanged("Cars");            }        }        public ICommand EnterDownCommand        {            get            {                if (enterDownCommand == null)                {                    enterDownCommand = new RelayMCommand<Car>(OnEnterDownCommand);                }                return enterDownCommand;            }        }        /// <summary>        /// Called when "Enter" key is down.         /// </summary>        /// <param name="obj"></param>        private void OnEnterDownCommand(Car obj)        {            //How do I get the text box value here?            Console.Write(">>"+obj.Name);        }        public void OnPropertyChanged(string name)        {            PropertyChangedEventHandler handler = PropertyChanged;            if (handler != null)            {                handler(this, new PropertyChangedEventArgs(name));            }        }    }}

----- Mainwindow ---

  <Window x:Class="TestMVVM.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:TestMVVM"        mc:Ignorable="d"        Title="MainWindow" Height="350" Width="525">    <Window.DataContext>        <local:MainViewModel x:Name ="MainVM"/>    </Window.DataContext>    <Grid>        <Grid.RowDefinitions>            <RowDefinition Height="*"/>            <RowDefinition Height="*"/>        </Grid.RowDefinitions>        <Grid Grid.Row="0">            <Viewbox>                <ItemsControl ItemsSource="{Binding Cars}" Margin="5" Width="200">                    <ItemsControl.ItemTemplate>                        <DataTemplate>                            <local:CarUserControl Margin="5"                                                  KeyDownCommand="{Binding Path=DataContext.EnterDownCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>                        </DataTemplate>                    </ItemsControl.ItemTemplate>                    <ItemsControl.ItemsPanel>                        <ItemsPanelTemplate>                            <StackPanel Orientation="Vertical" IsItemsHost="True" />                        </ItemsPanelTemplate>                    </ItemsControl.ItemsPanel>                </ItemsControl>            </Viewbox>        </Grid>    </Grid></Window>

---继电器命令---

   using System;using System.Threading;using System.Windows.Input;namespace TestMVVM{    /// <summary>    /// Same as the Relay Command, except this handles an array of generic type <T>    /// </summary>    /// <typeparam name="T">Generic type parameter</typeparam>    public class RelayMCommand<T> : ICommand    {        private Predicate<T> _canExecute;        private Action<T> _execute;        public RelayMCommand(Action<T> execute, Predicate<T> canExecute = null)        {            _execute = execute;            _canExecute = canExecute;        }        private void Execute(T parameter)        {            _execute(parameter);        }        private bool CanExecute(T parameter)        {            return _canExecute == null ? true : _canExecute(parameter);        }        public bool CanExecute(object parameter)        {            return parameter == null ? false : CanExecute((T)parameter);        }        public void Execute(object parameter)        {            _execute((T)parameter);        }        public event EventHandler CanExecuteChanged;        public void RaiseCanExecuteChanged()        {            var temp = Volatile.Read(ref CanExecuteChanged);            if (temp != null)            {                temp(this, new EventArgs());            }        }    }}

看答案

一个 UserControl 可能会继承它 DataContext 从父窗口或当前项目 ItemsControl.

因此,如果您束缚您的 ItemsControl 到一个 IEnumerable<Car>,每个实例的 CarUserControl 可以直接与 Name 相应的属性 Car 目的:

<TextBox Text="{Binding Name}"             Grid.Column="1" Background="#FFE8D3D3" BorderThickness="0">    <TextBox.InputBindings>        <KeyBinding Key="Enter"                     Command="{Binding KeyDownCommand, ElementName=thisUC}"                     CommandParameter="{Binding}"/>    </TextBox.InputBindings></TextBox>

这是因为 UserControl 自动继承 DataContext 来自其父元素,这是相应的 Car 对象 ItemsControl 在这种情况下。

有关在ViewModel中访问USERCONTROL的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  3. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  4. ruby - 有没有办法从 ruby​​ case 语句中访问表达式? - 2

    我想从then子句中访问c​​ase语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案

  5. ruby - 从外部访问类的实例变量 - 2

    我理解(我认为)Ruby中类变量和类的实例变量之间的区别。我想知道如何从该类外部访问该类的实例变量。从内部(即在类方法中而不是实例方法中),它可以直接访问,但是从外部,有没有办法做MyClass.class.[@$#]variablename?我没有任何具体原因要这样做,只是学习Ruby并想知道是否可行。 最佳答案 classMyClass@my_class_instance_var="foo"class上述yield:>>foo我相信Arkku演示了如何从类外部访问类变量(@@),而不是类实例变量(@)。我从这篇文章中提取了上述内

  6. ruby-on-rails - 使用 HTTP.get_response 检索 Facebook 访问 token 时出现 Rails EOF 错误 - 2

    我试图在我的网站上实现使用Facebook登录功能,但在尝试从Facebook取回访问token时遇到障碍。这是我的代码:ifparams[:error_reason]=="user_denied"thenflash[:error]="TologinwithFacebook,youmustclick'Allow'toletthesiteaccessyourinformation"redirect_to:loginelsifparams[:code]thentoken_uri=URI.parse("https://graph.facebook.com/oauth/access_token

  7. ruby - 使用 Class.new 时访问外部范围 - 2

    是否有可能以某种方式访问​​Class.new范围内的a?a=5Class.new{defb;aend}.new.b#NameError:undefinedlocalvariableormethod`a'for#:0x007fa8b15e9af0>#:in`b' 最佳答案 即使@MarekLipka的回答是正确的——改变变量范围总是有风险的。这是可行的,因为每个block都带有创建它的上下文,因此您的局部变量a突然变得不那么局部了——它变成了一个“隐藏的”全局变量:a=5object=Class.new{define_method(

  8. ruby - 使用访问器方法即时创建对象 - 2

    使用散列定义的访问器方法动态创建对象的最简单方法是什么?例如,如果我有一个散列:{foo:"Foo",bar:"Bar"}我想要一个具有访问器方法foo、foo=、bar和bar=的对象,其初始值分别为"Foo"和"Bar"。我可以想到这样做:moduleObjectWithAccessordefself.newh;Struct.new(*h.keys).new(*h.values)endendo=ObjectWithAccessor.new(foo:"Foo",bar:"Bar")o.foo#=>"Foo"但是,我不需要它们的多个实例具有相同的特定键集,而是希望每次都使用可能不同的键

  9. ruby - 404 未找到,但可以从网络浏览器正常访问 - 2

    我在这方面尝试了很多URL,在我遇到这个特定的之前,它们似乎都很好:require'rubygems'require'nokogiri'require'open-uri'doc=Nokogiri::HTML(open("http://www.moxyst.com/fashion/men-clothing/underwear.html"))putsdoc这是结果:/Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:353:in`open_http':404NotFound(OpenURI::HT

  10. ruby-on-rails - "undefined method ` stub_request '"访问 RSpec 支持文件中的方法时 - 2

    我的Ruby-on-Rails项目中有以下文件结构,用于规范:/spec/msd/serviceservice_spec.rb/support/my_modulerequests_stubs.rb我的request_stubs.rb有:moduleMyModule::RequestsStubsmodule_functiondeflist_clientsurl="dummysite.com/clients"stub_request(:get,url).to_return(status:200,body:"clientsbody")endend在我的service_spec.rb我有:re

随机推荐