gpt4 book ai didi

c# - 如何仅从 ViewModel 以编程方式突出显示 DataGrid 行?

转载 作者:太空宇宙 更新时间:2023-11-03 22:48:12 25 4
gpt4 key购买 nike

SelectedItem 属性绑定(bind)不会导致其 DataGrid 行在初始加载时突出显示。

我有一个绑定(bind)到 SelectedItem 的 DataGrid,在我再次单击它之前它不会突出显示。我想我有一个操作顺序问题——因为所有 ViewModel 代码都在 View 呈现之前运行。单击一行(即使是已在 SelectedAccount Prop 中的同一行)后它工作正常,但我需要能够突出显示 VM 中的一行。

我可以轻松验证 SelectedAccount 属性不为空,因为还有其他 ViewModel 通过 PubSubEvents 显示它的值。

我已经尝试了几种解决方法,到目前为止我唯一能够让它工作的方法感觉很脏:

using ApplicationName.UI.ViewModels;
public partial class AccountsView : UserControl
{
public AccountsView()
{
InitializeComponent();
Loaded += AccountsView_Loaded;
}

private void AccountsView_Loaded(object sender, RoutedEventArgs e)
{
AccountsViewModel viewModel = (AccountsViewModel)DataContext;
AccountsDataGrid.SelectedItem = viewModel.SelectedAccount;
AccountsDataGrid.Focus();
UpdateLayout();
}
}

我不喜欢这样,因为它会导致 OnPropertyChanged 事件触发两次,一次是在 View 加载之前,一次是在上述 hack 之后。这会触发 SQL 调用,所以我想避免这种情况。我还认为 MVVM 的目的是将 View 与 View 模型分离,但也许我没有像我想的那样理解这一点。

这是 DataGrid 的 XAML:

<ScrollViewer Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="5,0">
<DataGrid Name="AccountsDataGrid"
ItemsSource="{Binding Accounts}"
SelectedItem="{Binding SelectedAccount}"
AutoGenerateColumns="False"
CanUserResizeColumns="True"
SelectionMode="Single"
SelectionUnit="FullRow">
<DataGrid.Columns>
<DataGridTextColumn Header="ClinicId"
TextBlock.TextAlignment="Center"
Width="75"
Binding="{Binding ClinicId}" />
<DataGridTextColumn Header="Account#"
Width="75"
Binding="{Binding AccountNumber}"/>
<DataGridTextColumn Header="LastName"
Width="1*"
Binding="{Binding LastName}" />
<DataGridTextColumn Header="FirstName"
Width="1*"
Binding="{Binding FirstName}" />
<DataGridTextColumn Header="Balance"
Width="Auto"
Binding="{Binding Balance}" />
<DataGridTextColumn Header="Follow Up"
Width="100"
Binding="{Binding FollowUpDate}"/>
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>

还有 ViewModel 中的初始 Load 方法,这是我要设置突出显示行的地方。

public void Load()
{
RefreshGrid();
SelectedAccount = Accounts.First();
_accountId = SelectedAccount.Id;
}

编辑

这个问题很微妙,但现在很有意义。

private Account _selectedAccount;

public Account SelectedAccount
{
get => _selectedAccount;
set => SetSelectedAccount(value);
}

private void SetSelectedAccount(Account value)
{
_selectedAccount = value;
OnPropertyChanged("_selectedAccount"); // <= whoops
if (_selectedAccount != null)
OnAccountSelected(
_selectedAccount.PrimaryKeyFields);
}

为私有(private)属性引发此事件没有意义,因为 View 看不到它,并且绑定(bind)到 SelectedAccount。将其更改为 OnPropertyChanged("SelectedAccount") 就可以了。

最佳答案

实现 INotifyPropertyChanged 应该足够了,这段代码对我有效,我正在使用 Command 调用 Load() 方法但您的代码中可能不需要它。

ViewModel 和 C# 代码:

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

DataContext = new ViewModel();
}
}

public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

public ViewModel()
{
Accounts = new List<Account>();

Accounts.AddRange(
Enumerable.Range(0, 10)
.Select(r => new Account
{
AccountNumber = r,
FirstName = $"First{r}",
LastName = $"Last{r}"
}));

LoadedCommand = new WpfCommand((param) => Load());
}

private void Load()
{
SelectedAccount = Accounts.FirstOrDefault(a => a.AccountNumber == 2);
}

public WpfCommand LoadedCommand { get; set; }

public List<Account> Accounts { get; set; }

private Account _selectedAccount = null;
public Account SelectedAccount
{
get { return _selectedAccount; }
set
{
_selectedAccount = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedAccount)));
}
}
}

public class Account
{
public int AccountNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}

public class WpfCommand : ICommand
{
private Action<object> _execute;
private Func<object, bool> _canExecute;

public event EventHandler CanExecuteChanged;

public WpfCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}

public void Execute(object parameter)
{
_execute?.Invoke(parameter);
}

public bool CanExecute(object parameter)
{
return _canExecute?.Invoke(parameter) ?? true;
}
}

XAML:

   <!--System.Windows.Interactivity.WPF nuget package-->
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

<DataGrid
ItemsSource="{Binding Accounts}"
SelectedItem="{Binding SelectedAccount}">

<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>

<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding AccountNumber}"/>
<DataGridTextColumn Binding="{Binding LastName}" />
<DataGridTextColumn Binding="{Binding FirstName}" />
</DataGrid.Columns>
</DataGrid>

关于c# - 如何仅从 ViewModel 以编程方式突出显示 DataGrid 行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48875073/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com