简体   繁体   English

如何从另一个类访问userControl中的某些属性?

[英]How can I access some properties in userControl from another class?

My program is consists of a userControl and a class in C# winform environment. 我的程序由一个userControl和一个在C#winform环境中的class组成。 when I click on a button in userControl , an instance of my class is created and the main process starts. 当我单击userControlbutton时,将创建我的class的实例,并且主过程启动。 I want to interact with my class with userControl through the program is running. 我想通过正在运行的程序与带有userControl class进行交互。 for example, I want to show some massages from class to a textBox property in the designed userControl . 例如,我想显示从class到设计的userControltextBox属性的一些消息。 I can not instantiate from my userControl in my class because it is wrong and can not access running userControl properties. 我不能从我的class userControl实例化,因为它是错误的,并且无法访问正在运行的userControl属性。 So, How can I do it? 那么,我该怎么办呢? Is it a good solution to set userControl a singleton class? userControl设置为单例类是一个好的解决方案吗? Do u recommend a better solution? 您是否建议一个更好的解决方案?

Edit: For more clarification: I want to call a method from the class and pass an argument ( string ) into it. 编辑: 为进一步说明:我想从class调用一个方法,并将一个参数( 字符串 )传递给它。 Then textBox in the userControl should show the passed argument! 然后textBoxuserControl应显示传递的参数! This procedure would be repeated whenever it has an output in the class ! 只要在class有输出,就将重复此过程!

Update: here is code sample: In the class definition: 更新:这是代码示例:在类定义中:

class MyClass
{
    public MyClass()
    {
        //do sth
        if (a condition)
        {
            //It is wrong to create an instance but I want to explain my purpose. It is what I need!
            searchPanel sp = new searchPanel();
            sp.showMessage("...");
        }
    }
}

And here is userControl: 这是userControl:

public partial class searchPanel : UserControl
{
    public searchPanel()
    {
        InitializeComponent();
    }
    public void showMessage(string message)
    {
        textBox.AppendText(message);
        textBox.AppendText(Environment.NewLine);
    }
}

So, How can I do it? 那么,我该怎么办呢?

You could do this by implementing events . 您可以通过实现事件来做到这一点。 This way you can signal every class that is subscribing to your " class " events when whatever you want happens. 这样,您可以在发生任何所需的事件时向正在订阅class ”事件的每个类发出信号。 Imagine your " class " just completes to sum up 10 integer numbers; 想象一下,您的“ class ”完成了对10个整数的累加; you fire a event informing this operation just happened. 您会触发一个事件,通知此操作刚刚发生。 Your " userControl " class is subscribing to this event and will be able to execute a function to change whatever control in the form you want. 您的“ userControl ”类正在订阅此事件,并且将能够执行一个函数来更改所需形式的任何控件。 By using events you keep class isolation, avoiding things like global state in your code. 通过使用事件,可以保持类隔离,避免代码中出现诸如全局状态之类的情况。

Is it a good solution to set userControl a singleton class? 将userControl设置为单例类是一个好的解决方案吗?

No, you should avoid using singleton as a pattern in your code. 不,您应该避免在代码中使用单例作为模式。 Above all using singleton as global state to expose your " class " to " userControl " is probably evidence of code smell 最重要的是,使用单例作为全局状态将您的“ class ”暴露给“ userControl ”可能是代码气味的证据

This is usually done using the WPF Command Pattern and binding ( Data Binding Overview ). 通常使用WPF命令模式和绑定( 数据绑定概述 )来完成此操作。 This is the recommended approach. 这是推荐的方法。

MainWindow.xaml MainWindow.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

  <SearchPanel />
</Window>

SearchPanel.xaml SearchPanel.xaml

<UserControl>
  <UserControl.DataContext>
    <ViewModel />
  </UserControl.DataContext>

  <StackPanel>

    <Button Command="{Binding ShowMessageCommand}" />

    <TextBlock Text="{Binding Message}" />
  <StackPanel>
</UserControl>

SearchPanel.xaml.cs SearchPanel.xaml.cs

public partial class SearchPanel : UserControl
{
  public SearchPanel()
  {
    InitializeComponent();
  } 
}

ViewModel.cs ViewModel.cs

class ViewModel : INotifyPropertyChanged
{
  private string message;
  public string Message
  {
    get => this.message;
    set
    {
      this.message = value;
      OnPropertyChanged();
    }
  }

  ICommand ShowMessageCommand => new RelayCommand(CreateMessage);


  // Command callback
  private void CreateMessage()
  {
    this.Message = "This is a message for display in the UI";
  }

  public event PropertyChangedEventHandler PropertyChanged;

  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
  {
    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

The helper class to create a reusable command: 帮助程序类创建可重用的命令:

RelayCommand.cs RelayCommand.cs

/// <summary>
/// An implementation independent ICommand implementation.
/// Enables instant creation of an ICommand without implementing the ICommand interface for each command.
/// The individual Execute() an CanExecute() members are supplied via delegates.
/// <seealso cref="System.Windows.Input.ICommand"/>
/// </summary>
/// <remarks>The type of <c>RelayCommand</c> actually is a <see cref="System.Windows.Input.ICommand"/></remarks>
public class RelayCommand : ICommand
{
  protected readonly Func<Task> executeAsyncNoParam;
  protected readonly Action executeNoParam;
  protected readonly Func<bool> canExecuteNoParam;
  private readonly Func<object, Task> executeAsync;
  private readonly Action<object> execute;
  private readonly Predicate<object> canExecute;
  /// <summary>
  /// Raised when RaiseCanExecuteChanged is called.
  /// </summary>
  public event EventHandler CanExecuteChanged
  {
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
  }
  /// <summary>
  /// Creates a new command that can always execute.
  /// </summary>
  /// <param name="execute">The execution logic.</param>
  public RelayCommand(Action<object> execute)
      : this(execute, (param) => true)
  {
  }
  /// <summary>
  /// Creates a new command that can always execute.
  /// </summary>
  /// <param name="executeNoParam">The execution logic.</param>
  public RelayCommand(Action executeNoParam)
      : this(executeNoParam, () => true)
  {
  }
  /// <summary>
  /// Creates a new command that can always execute.
  /// </summary>
  /// <param name="executeAsync">The awaitable execution logic.</param>
  public RelayCommand(Func<object, Task> executeAsync)
      : this(executeAsync, (param) => true)
  {
  }
  /// <summary>
  /// Creates a new command that can always execute.
  /// </summary>
  /// <param name="executeAsyncNoParam">The awaitable execution logic.</param>
  public RelayCommand(Func<Task> executeAsyncNoParam)
      : this(executeAsyncNoParam, () => true)
  {
  }
  /// <summary>
  /// Creates a new command.
  /// </summary>
  /// <param name="executeNoParam">The execution logic.</param>
  /// <param name="canExecuteNoParam">The execution status logic.</param>
  public RelayCommand(Action executeNoParam, Func<bool> canExecuteNoParam)
  {
    this.executeNoParam = executeNoParam ?? throw new ArgumentNullException(nameof(executeNoParam));
    this.canExecuteNoParam = canExecuteNoParam;
  }
  /// <summary>
  /// Creates a new command.
  /// </summary>
  /// <param name="execute">The execution logic.</param>
  /// <param name="canExecute">The execution status logic.</param>
  public RelayCommand(Action<object> execute, Predicate<object> canExecute)
  {
    this.execute = execute ?? throw new ArgumentNullException(nameof(execute));
    this.canExecute = canExecute;
  }
  /// <summary>
  /// Creates a new command.
  /// </summary>
  /// <param name="executeAsyncNoParam">The awaitable execution logic.</param>
  /// <param name="canExecuteNoParam">The execution status logic.</param>
  public RelayCommand(Func<Task> executeAsyncNoParam, Func<bool> canExecuteNoParam)
  {
    this.executeAsyncNoParam = executeAsyncNoParam ?? throw new ArgumentNullException(nameof(executeAsyncNoParam));
    this.canExecuteNoParam = canExecuteNoParam;
  }
  /// <summary>
  /// Creates a new command.
  /// </summary>
  /// <param name="executeAsync">The awaitable execution logic.</param>
  /// <param name="canExecute">The execution status logic.</param>
  public RelayCommand(Func<object, Task> executeAsync, Predicate<object> canExecute)
  {
    this.executeAsync = executeAsync ?? throw new ArgumentNullException(nameof(executeAsync));
    this.canExecute = canExecute;
  }
  /// <summary>
  /// Determines whether this RelayCommand can execute in its current state.
  /// </summary>
  /// <returns>true if this command can be executed; otherwise, false.</returns>
  public bool CanExecute()
  {
    return this.canExecuteNoParam == null || this.canExecuteNoParam();
  }

  /// <summary>
  /// Executes the RelayCommand on the current command target.
  /// </summary>
  public async void Execute()
  {
    if (this.executeAsyncNoParam != null)
    {
      await ExecuteAsync();
      return;
    }
    this.executeNoParam();
  }

  /// <summary>
  /// Executes the RelayCommand on the current command target.
  /// </summary>
  public async Task ExecuteAsync()
  {
    if (this.executeAsyncNoParam != null)
    {
      await this.executeAsyncNoParam();
      return;
    }

    await Task.Run(() => this.executeNoParam());
  }
  /// <summary>
  /// Determines whether this RelayCommand can execute in its current state.
  /// </summary>
  /// <param name="parameter">
  /// Data used by the command. If the command does not require data to be passed, 
  /// this object can be set to null.
  /// </param>
  /// <returns>true if this command can be executed; otherwise, false.</returns>
  public bool CanExecute(object parameter)
  {
    return this.canExecute == null || this.canExecute(parameter);
  }

  /// <summary>
  /// Executes the RelayCommand on the current command target.
  /// </summary>
  /// <param name="parameter">
  /// Data used by the command. If the command does not require data to be passed, 
  /// this object can be set to null.
  /// </param>
  public async void Execute(object parameter)
  {
    if (parameter == null)
    {
      Execute();
      return;
    }

    if (this.executeAsync != null)
    {
      await ExecuteAsync(parameter);
      return;
    }
    this.execute(parameter);
  }

  /// <summary>
  /// Executes the RelayCommand on the current command target.
  /// </summary>
  /// <param name="parameter">
  /// Data used by the command. If the command does not require data to be passed, 
  /// this object can be set to null.
  /// </param>
  public async Task ExecuteAsync(object parameter)
  {
    if (this.executeAsync != null)
    {
      await this.executeAsync(parameter);
      return;
    }

    await Task.Run(() => this.execute(parameter));
  }
}

I recommend some reading on MVVM and Commanding eg Basic MVVM and ICommand Usage Example or Commanding Overview 我建议您阅读一些有关MVVM和命令的内容,例如, 基本MVVM和ICommand使用示例命令概述


Alternative approach using a simple Button.Click event handler: 使用简单的Button.Click事件处理程序的替代方法:

SearchPanel.xaml SearchPanel.xaml

<UserControl>
  <UserControl.DataContext>
    <ViewModel />
  </UserControl.DataContext>

  <StackPanel>

    <Button Click="ShowMessage_OnButtonClick" />

    <TextBlock x:Name="MessageTextBlock" />
  <StackPanel>
</UserControl>

SearchPanel.xaml.cs SearchPanel.xaml.cs

public partial class SearchPanel : UserControl
{
  public SearchPanel()
  {
    InitializeComponent();
  } 

  private void ShowMessage_OnButtonClick(object sender, RoutedEventArgs e)
  {
    this.MessageTextBlock = "This is a message for display in the UI";
  }
}

Events and XAML code-behind 事件和XAML背后的代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何向UserControl添加一些属性? - How can i add some properties to UserControl? 如何在C#中从IDataReader Func调用的另一个属性中访问类属性 - How can i access a class properties from within another one called from a IDataReader Func in C# 如何从另一个类访问一个类的属性 - How to access the properties in a class from another class 我如何从flowLayoutPanel获取添加的usercontrol属性 - how can i get my added usercontrol properties from flowLayoutPanel 如何从App_code中的类内部访问UserControl? - How can I access a UserControl from inside a class in App_code? 如何从.net类访问UserControl资源 - How do I access a UserControl resource from a .net class 如何从一个UserControl访问另一个UserControl的占位符? - How to access Placeholder from one UserControl from another UserControl? 如何使用事件从UserControl调用方法到另一个UserControl或另一个aspx.Page? - How can i call method from UserControl to another UserControl or another aspx.Page using Events? 如果这些属性从某个基类继承,我怎么能递归搜索C#中的属性? - How can I recursively search properties in C# only if those properties inherit from some base class? 我如何从另一个类访问一个类数组 - How can I access a class array from another class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM