У меня есть проект Winui 3, в котором я использую шаблон MVVM с помощью набора инструментов MVVM от Microsoft. Я создал UserControl, который имеет 2 DependencyProperties типа ICommand. Чтобы, когда я использую этот элемент управления в своем представлении, я мог выполнить код для нажатия кнопок из модели представления, чтобы соответствовать принципам mvvm.
Пользовательское управление:
public sealed partial class MyDialog : UserControl
{
public static readonly DependencyProperty YesSelectedCommandProperty =
DependencyProperty.Register("YesSlectedCommand", typeof(ICommand), typeof(AddinAutoAttachDialog), new PropertyMetadata(null, OnYesCommandChanged));
public static readonly DependencyProperty NoSelectedCommandProperty =
DependencyProperty.Register("NoSelectedCommand", typeof(ICommand), typeof(AddinAutoAttachDialog), new PropertyMetadata(null, OnNoCommandChanged));
public ICommand YesSlectedCommand
{
get { return (ICommand)GetValue(YesSelectedCommandProperty); }
set { SetValue(YesSelectedCommandProperty, value); }
}
public ICommand NoSlectedCommand
{
get { return (ICommand)GetValue(NoSelectedCommandProperty); }
set { SetValue(NoSelectedCommandProperty, value); }
}
public MyDialog()
{
this.InitializeComponent();
}
Соответствующий код xaml:
<Button Content = "Yes"
Command = "{x:Bind YesSlectedCommand, Mode=OneTime}"/>
<Button Content = "No"
Command = "{x:Bind NoSlectedCommand, Mode=OneTime}" />
Я использую это, на мой взгляд, так:
<Window ....>
<components:MyDialog Visibility = "{x:Bind MainViewModel.ShowMyDialog, Mode=OneWay}"
YesSlectedCommand = "{x:Bind MainViewModel.YesSelected, Mode=OneWay}"
NoSlectedCommand = "{x:Bind MainViewModel.NoSelected, Mode=OneWay}" />
<InfoBar IsOpen = "True"
Severity = "Success"
Title = "..."
Visibility = "{x:Bind MainViewModel.ShowSuccessInfoBar, Mode=OneWay}"/>
<InfoBar IsOpen = "True"
Severity = "Error"
Title = "..."
Visibility = "{x:Bind MainViewModel.ShowErrorInfoBar, Mode=OneWay}" />
</Window>
Затем в моей модели представления я выполняю аналогичный код (в основном изменяя видимость элементов пользовательского интерфейса):
internal partial class MainViewModel : ObservableObject
{
[ObservableProperty]
private bool showMyDialog = false;
[ObservableProperty]
private bool showSuccessInfoBar = false;
[ObservableProperty]
private bool showErrorInfoBar = false;
[RelayCommand]
private void YesSelected()
{
bool succeeded = ExecuteSomeOperations();
ShowMyDialog = false;
ShowSuccessInfoBar = succeeded;
ShowErrorInfoBar = !succeeded;
}
[RelayCommand]
private void NoSelected()
{
ShowMyDialog = false;
ShowErrorInfoBar = true;
}
}
Как ни странно, мое приложение иногда вылетает, когда я нажимаю кнопку «Нет», а иногда и кнопку «Да». Но в других случаях все отображается правильно.
Когда я подключил свой отладчик, единственное, что я увидел, была эта строка сообщения: Программа «[9964] MyWindow.exe» завершилась с кодом 3221226107 (0xc000027b). Я проверил средство просмотра событий, где нашел это:
Faulting application name: MyWindow.exe, version: 1.0.0.0, time stamp: 0x661f0000
Faulting module name: Microsoft.ui.xaml.dll, version: 3.1.4.0, time stamp: 0x343afd70
Exception code: 0xc000027b
Fault offset: 0x00000000003b9584
Faulting process id: 0x0x4930
Faulting application start time: 0x0x1DAFE12C2C9EF06
Faulting module path: \...\Microsoft.ui.xaml.dll
Faulting package full name:
Faulting package-relative application ID:
Я попытался обернуть его в блок try catch, но никаких исключений не было обнаружено, и мой код внутри команд, которые изменяют видимость элементов пользовательского интерфейса в методах Yes/NoSelected, мог выполняться успешно. Я также пытался найти ошибки привязки, потому что, похоже, происходит сбой, когда я изменяю пользовательский интерфейс. (кстати, я не изменяю пользовательский интерфейс из другого потока), поэтому я также попробовал это:
public App()
{
this.InitializeComponent();
this.DebugSettings.BindingFailed += (s, e) =>
{
File.AppendAllText(LogPath, $"BindingFailed: {e.Message}");
};
}
Но в моем файле журнала не было журналов об ошибке привязки.
В чем здесь может быть проблема?
«ДаSlectedCommand» и «NoSlectedCommand» — это опечатки, верно?
У вас все еще есть проблемы, если YesSlectedCommand
и NoSlectedCommand
в вашей модели представления пусты?
@SimonMourier Проблема в том, что когда я отлаживаю его и нажимаю на одну из кнопок, происходит сбой. После этого выходные данные отладки не показали никаких исключений в журнале, только эта строка в конце: Программа «[9964] MyWindow.exe» завершилась с кодом 3221226107 (0xc000027b).
@AndrewKeepCoding Да, это всего лишь опечатка. Я просто попытался удалить ненужную часть кода и допустил опечатку. Когда я попытался удалить тело методов Yes/NoSlectedCommand, проблема не возникла. Кажется, что когда свойства, связанные с данными (ShowMyDialog, ShowErrorInfoBar), обновляются, приложение иногда выходит из строя. Я поделился дополнительным кодом в своем вопросе об этой части в представлении и модели представления.
Можете ли вы поделиться кодом вашего диалога?
Проблема была в привязке данных. Я забыл использовать преобразователь логических значений в видимость для видимости моих элементов управления. Но в моем случае корневым элементом, на мой взгляд, является окно, где невозможно использовать x:bind с конвертером, поэтому мне пришлось переключиться на расширение разметки Binding. Поскольку контекст данных для x:bind и Binding различен, мне пришлось использовать контекст данных из сетки моего контейнера, где он установлен.
Поэтому я изменил код из этого:
<InfoBar IsOpen = "True"
Severity = "Success"
Title = "..."
Visibility = "{x:Bind MainViewModel.ShowSuccessInfoBar, Mode=OneWay}"/>
на это:
<InfoBar IsOpen = "True"
Severity = "Success"
Title = "..."
Visibility = "{Binding ElementName=myGrid, Path=DataContext.ShowSuccessInfoBar, Mode=OneWay, Converter = {StaticResource BooleanToVisibilityConverter}}" />
Это решило проблему спорадических сбоев, но я до сих пор не понимаю, почему это вообще работало, потому что иногда это работало без проблем.
Встроенный преобразователь bool в видимость должен работать. Я не уверен, что проблема здесь в отсутствующем конвертере.
Ну, это не сработало, потому что после того, как я начал использовать свой, проблема исчезла.
Мы будем рады поделиться своим решением здесь. Пожалуйста, не забудьте принять свой ответ, поскольку решение вам подходит.
С точки зрения Windows, исключения .NET в WinUI3 в конечном итоге не отображаются в средстве просмотра событий как нечто сверхполезное. Вам следует отлаживать приложение, и при отладке вы должны получить более читаемое исключение .NET.