[英]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. 当我单击userControl
的button
时,将创建我的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
到设计的userControl
的textBox
属性的一些消息。 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! 然后textBox
的userControl
应显示传递的参数! 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";
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.