用户控制MVVM中的执行方法

发布于 2024-11-28 22:13:13 字数 3750 浏览 0 评论 0原文

我正在开发我的第一个 MVVM 应用程序,但无法使其正常工作。

在我的主窗口中,有一个按钮可以执行返回自定义数据表类型对象的 SQL 命令。

该窗口还包含一个用户控件,该控件由一些列标题和一个托管 DataGridView 的 Windows 窗体组成。我需要以某种方式告诉用户控件执行将数据传递到 DataGridView 的方法,以便它可以更新其值。

我尝试在 WPF 网格控件上创建一个绑定到视图模型数据的依赖属性,但它无法正确更新。

我怎样才能让它发挥作用?

--编辑--

这是我的 LiteGrid 用户控件的 XAML -

<UserControl x:Class="ReportUtility.Controls.LiteGrid.LiteGrid"
         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:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
         xmlns:lite="clr-namespace:ReportUtility.Controls.LiteGrid"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <ScrollViewer x:Name="_scroll" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
        <ItemsControl ItemsSource="{Binding Columns}" Grid.Row="0" Background="AliceBlue">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate> 
                        <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </ScrollViewer>
    <WindowsFormsHost Background="White" Grid.Row="1">
        <lite:LiteGridView x:Name="_liteGridView"/>
    </WindowsFormsHost>
</Grid>

我的主要视图模型是:

public class MainWindowViewModel : DependencyObject
{
    private readonly ILiteTableSource _source;

    public ICommand ExecuteQueryCommand { get; set; }
    public LiteGridViewModel Grid { get; set; }
    public string SqlCommandText { get; set; }

    public MainWindowViewModel(ILiteTableSource source)
    {
        this.ExecuteQueryCommand = new ExecuteQueryCommand(this);

        _source = source;
        _source.DataArrived+=new Action<DataSources.LiteSource.LiteTable>(_source_DataArrived);
    }

    public void ExecuteQuery()
    {
        _source.Connection = new ServerConnection();
        _source.CommandText = this.SqlCommandText;
        _source.ExecuteQuery();
    }

    public LiteTable Results
    {
        get { return (LiteTable)GetValue(ResultsProperty); }
        set { SetValue(ResultsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Results.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ResultsProperty =
        DependencyProperty.Register("Results", typeof(LiteTable), typeof(MainWindowViewModel), new UIPropertyMetadata(null));

    void _source_DataArrived(LiteTable data)
    {

        this.Results = data;
    }
}

和 XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="50"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Button Grid.Row="0" Content="TestButton" HorizontalAlignment="Stretch" Command="{Binding ExecuteQueryCommand}"/>
    <TextBox Grid.Row="1" Text="{Binding Path=SqlCommandText, UpdateSourceTrigger=PropertyChanged}"/>
    <lite:LiteGrid Grid.Row="2" Data="{Binding Data, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>

I am working on my first MVVM application and am having trouble getting it to work properly.

In my main window, I have a button that executes a SQL command that returns a custom data table type object.

The window also contains a user control that consists of a some column headers and a windows forms hosted DataGridView. I need to somehow tell the user control to execute a method that passes the data to the DataGridView so it can update it's values.

I tried creating a dependency property on my WPF Grid control that is bound to the data of my viewmodel, but it is not updating properly.

How can I get this to work?

--EDIT--

Here is the XAML for my LiteGrid usercontrol -

<UserControl x:Class="ReportUtility.Controls.LiteGrid.LiteGrid"
         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:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
         xmlns:lite="clr-namespace:ReportUtility.Controls.LiteGrid"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <ScrollViewer x:Name="_scroll" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
        <ItemsControl ItemsSource="{Binding Columns}" Grid.Row="0" Background="AliceBlue">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate> 
                        <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </ScrollViewer>
    <WindowsFormsHost Background="White" Grid.Row="1">
        <lite:LiteGridView x:Name="_liteGridView"/>
    </WindowsFormsHost>
</Grid>

My main view model is:

public class MainWindowViewModel : DependencyObject
{
    private readonly ILiteTableSource _source;

    public ICommand ExecuteQueryCommand { get; set; }
    public LiteGridViewModel Grid { get; set; }
    public string SqlCommandText { get; set; }

    public MainWindowViewModel(ILiteTableSource source)
    {
        this.ExecuteQueryCommand = new ExecuteQueryCommand(this);

        _source = source;
        _source.DataArrived+=new Action<DataSources.LiteSource.LiteTable>(_source_DataArrived);
    }

    public void ExecuteQuery()
    {
        _source.Connection = new ServerConnection();
        _source.CommandText = this.SqlCommandText;
        _source.ExecuteQuery();
    }

    public LiteTable Results
    {
        get { return (LiteTable)GetValue(ResultsProperty); }
        set { SetValue(ResultsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Results.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ResultsProperty =
        DependencyProperty.Register("Results", typeof(LiteTable), typeof(MainWindowViewModel), new UIPropertyMetadata(null));

    void _source_DataArrived(LiteTable data)
    {

        this.Results = data;
    }
}

And the XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="50"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Button Grid.Row="0" Content="TestButton" HorizontalAlignment="Stretch" Command="{Binding ExecuteQueryCommand}"/>
    <TextBox Grid.Row="1" Text="{Binding Path=SqlCommandText, UpdateSourceTrigger=PropertyChanged}"/>
    <lite:LiteGrid Grid.Row="2" Data="{Binding Data, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烟火散人牵绊 2024-12-05 22:13:13

既然您有一个与 LiteGrid 配合使用的 LiteGridViewModel,为什么不直接从 ViewModel 执行命令呢?

使用您问题中发布的代码,我会:

将其添加到资源中,以确保使用 LiteView 绘制 LiteGridViewModel

<Window.Resources> <!-- Or Grid.Resources if you prefer -->
    <DataTemplate DataType="{x:Type lite:LiteGridViewModel}">
        <lite:LiteGrid />
    </DataTemplate>
</Window.Resources>

替换 MainView 中的控件,带有 ContentControl 来显示 ViewModel

<ContentControl Content="{Binding Grid}" />

删除 MainViewModel 上的 Data 属性,因为它应存储在LiteGridViewModel,而不是 MainViewModel

并且在您的 MainWindowViewModel 中使用 LiteGridViewModel,而不是尝试通过看法

Grid = new LiteGridViewModel();

void _source_DataArrived(LiteTable data)
{
    Grid.Data = data;  // Fill property in ViewModel
    Grid.UpdateData(); // Call command on ViewModel
}

Since you have a LiteGridViewModel to go with your LiteGrid, why not just execute the command from the ViewModel?

Using the code posted in your question, I would:

Add this to the Resources to make sure that LiteGridViewModel is drawn using LiteView

<Window.Resources> <!-- Or Grid.Resources if you prefer -->
    <DataTemplate DataType="{x:Type lite:LiteGridViewModel}">
        <lite:LiteGrid />
    </DataTemplate>
</Window.Resources>

Replace the <lite:LiteGrid ... /> control in the MainView with a ContentControl to display the ViewModel

<ContentControl Content="{Binding Grid}" />

Remove the Data Property on the MainViewModel since it should be stored in LiteGridViewModel, not MainViewModel

And in your MainWindowViewModel work with the LiteGridViewModel instead of trying to work with the ViewModel via the View

Grid = new LiteGridViewModel();

void _source_DataArrived(LiteTable data)
{
    Grid.Data = data;  // Fill property in ViewModel
    Grid.UpdateData(); // Call command on ViewModel
}
花开柳相依 2024-12-05 22:13:13
public LiteTable Data
{
    get { return (LiteTable)GetValue(DataProperty); }
    set 
    {
        object oldvalue = Data;
        SetValue(DataProperty, value);
        OnPropertyChanged(new DependencyPropertyChangedEventArgs(DataProperty, oldvalue, value));
    }
}

// Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
    DependencyProperty.Register("Data", typeof(LiteTable), typeof(LiteGrid), new UIPropertyMetadata(null));

试试这个...

public LiteTable Data
{
    get { return (LiteTable)GetValue(DataProperty); }
    set 
    {
        object oldvalue = Data;
        SetValue(DataProperty, value);
        OnPropertyChanged(new DependencyPropertyChangedEventArgs(DataProperty, oldvalue, value));
    }
}

// Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
    DependencyProperty.Register("Data", typeof(LiteTable), typeof(LiteGrid), new UIPropertyMetadata(null));

try this...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文