SelectedItem属性绑定未导致其DataGrid行在初始加载时突出显示。
我有一个带有SelectedItem绑定的DataGrid,直到我再次点击它才会突出显示。我认为我有一个操作顺序问题 - 来自所有ViewModel代码在Views被渲染之前运行的事实。一旦我点击一行(甚至是已经在SelectedAccount道具中的那一行),它工作正常,但我需要能够从VM突出显示一行。
我可以轻松验证SelectedAccount属性不为null,因为还有其他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
事件触发两次,一次在视图加载之前,以及在上面的hack之后再次触发。这会触发SQL调用,所以我想避免这种情况。我还认为MVVM的意思是将视图与视图模型分离,但也许我并不像我想的那样理解它。
这是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);
}
为私有属性引发此事件没有意义,因为视图无法看到它,并且绑定到SelectedAccount。将它更改为OnPropertyChanged(“SelectedAccount”)就可以了。
答案 0 :(得分:2)
实施$scope.changeBoletas=function(){
$scope.boleta=[];
$scope.boleta.push({comision:123});
}
应该足够了,此代码适用于我,我使用INotifyPropertyChanged
调用Command
方法,但可能不需要在你的代码中。
ViewModel和C#代码:
Load()
XAML:
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;
}
}
答案 1 :(得分:1)
在视图模型中,使用框架的RaisePropertyChanged();
函数(或等效函数)。在DataGrid
元素的代码隐藏中,请尝试以下代码:
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
for (int i = 0; i < DataGrid.Items.Count; i++)
{
DataGridRow row = (DataGridRow)DataGrid.ItemContainerGenerator.ContainerFromIndex(i);
TextBlock cellContent = DataGrid.Columns[0].GetCellContent(row) as TextBlock;
if (cellContent != null && cellContent.Text.Equals(DataGrid.SelectedItem))
{
object item = DataGrid.Items[i];
DataGrid.SelectedItem = item;
DataGrid.ScrollIntoView(item);
row.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
break;
}
}
}
在我的示例中,我使用了通用字符串名称列表,因此您可能需要更改行TextBlock cellContent = DataGrid.Columns[0].GetCellContent(row) as TextBlock;
和cellContent.Text.Equals(DataGrid.SelectedItem))
以符合您的行选择标准。
如果您不想使用代码隐藏,另一种选择是附加行为,或多或少做同样的事情。