Новичок в программировании WPF. Я работаю в WinForms. У меня есть два рабочих проекта/решения WinForms, которые я хочу преобразовать в WPF. Мне удалось пройти через XMAL и MainWindowViewModel, но я уперся в стену. Проверил Интернет на наличие рабочего кода, позволяющего изменить текст «Кнопки» при нажатии. Моя проблема в том, что я не могу изменить текст контекста кнопки на что-то другое. Я хотел бы изменить текст кнопки с текущего на «Выполняется...» при нажатии, а затем, как только команда завершится, вернуться к предыдущему.
Мой XAML:
<Window x:Class = "XPR_AppBuilderSuiteWpf.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local = "clr-namespace:XPR_AppBuilderSuiteWpf"
mc:Ignorable = "d"
Title = "XPR-AppBuilder Suite WPF Version" Height = "680" Width = "820">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Window.Resources>
<Style x:Key = "GroupToggleStyle" TargetType = "RadioButton"
BasedOn = "{StaticResource {x:Type ToggleButton}}">
<Setter Property = "Foreground" Value = "Blue"/>
<Style.Triggers>
<DataTrigger Binding = "{Binding IsErrorProcess}"
Value = "True">
<DataTrigger.Setters>
<Setter Property = "Foreground" Value = "Red"/>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Background = "Beige">
<Grid.RowDefinitions>
<RowDefinition Height = "250"/>
<RowDefinition Height = "70"/>
<RowDefinition Height = "260"/>
<RowDefinition Height = "80"/>
</Grid.RowDefinitions>
<StackPanel Orientation = "Horizontal" Background = "LightBlue" Grid.Row = "0" Height = "295" Margin = "0,0,0,4">
<GroupBox x:Name = "groupBox" Header = "AB XML Reader" Width = "778" Height = "120" Margin = "10,-160,10,14">
<StackPanel Height = "251">
<Button x:Name = "btnSeletXMLFile" Content = "{Binding sSelectXMLFile}" Command = "{Binding btnSelectXMLFile}" HorizontalAlignment = "Left"
Margin = "5,10,0,0" VerticalAlignment = "Top" Height = "20" Width = "76"/>
<Button x:Name = "btnFindTags" Content = "{Binding sFindTags}" Command = "{Binding btnFindTags}" Margin = "-452,-20,0,0" Height = "20" Width = "72"/>
<Button x:Name = "btnSelectFolder" Content = "{Binding sSelectFolder}" Command = "{Binding btnSelectFolder}" HorizontalAlignment = "Left"
Margin = "245,-19,0,25" VerticalAlignment = "Top" Height = "20" Width = "72"/>
<CheckBox x:Name = "chkBCallflowXML" Content = "Run Callflow XML" IsChecked = "{Binding IschkBCallflowXML}" IsEnabled = "{Binding IsProcessingData}"
HorizontalAlignment = "Left" Margin = "5,-14,0,0" VerticalAlignment = "Top" Height = "15" Width = "113"/>
<CheckBox x:Name = "chkBWorkspaceXML" Content = "Run Worksapce XML" IsChecked = "{Binding IschkBWorkspaceXML}" IsEnabled = "{Binding IsProcessingData}" HorizontalAlignment = "Left" Margin = "126,-14,0,0" VerticalAlignment = "Top" Height = "15" Width = "130"/>
<CheckBox x:Name = "chkBAppXML" Content = "Run Application XML" IsChecked = "{Binding IschkBAppXML}" IsEnabled = "{Binding IsProcessingData}" HorizontalAlignment = "Left" Margin = "268,-14,0,0" VerticalAlignment = "Top" Height = "15" Width = "131"/>
<CheckBox x:Name = "chkBVariablesXML" Content = "Run Variables XML" IsChecked = "{Binding IschkBVariablesXML}" IsEnabled = "{Binding IsProcessingData}" HorizontalAlignment = "Left" Margin = "407,-14,0,0" VerticalAlignment = "Top" Height = "15" Width = "125"/>
<CheckBox x:Name = "chkBDontAddFilename" Content = "Don't add file name" IsChecked = "{Binding IschkBDontAddFilename}" IsEnabled = "{Binding IsProcessingData}" HorizontalAlignment = "Left" Margin = "534,-14,0,0" VerticalAlignment = "Top"/>
<Label x:Name = "label" Content = "Filter exclusion" HorizontalAlignment = "Left" Margin = "5,6,0,0" VerticalAlignment = "Top"/>
<TextBox x:Name = "txtBFilter" Text = "{Binding txtBFilter}" HorizontalAlignment = "Left" Margin = "96,-20,0,0" TextWrapping = "Wrap" VerticalAlignment = "Top" Width = "120"/>
</StackPanel>
</GroupBox>
<Label x:Name = "label2" Content = "Result window:" HorizontalAlignment = "Left" Margin = "-786,137,0,0" VerticalAlignment = "Top"/>
<TextBox x:Name = "txtBResult" Text = "{Binding txtBResult}" HorizontalAlignment = "Left" Margin = "-777,164,19,0" TextWrapping = "Wrap" VerticalAlignment = "Top" Width = "762" Height = "50"/>
</StackPanel>
<Label x:Name = "lblStatus" Content = "Status:" Margin = "20,5,720,0" VerticalAlignment = "Top" Height = "30" Grid.Row = "1"/>
<TextBox x:Name = "txtBStatus" Text = "{Binding txtBStatus}" Grid.Row = "1" Margin = "13,33,0,0" HorizontalAlignment = "Left" VerticalAlignment = "Top" Height = "30" Width = "777"/>
<StackPanel Orientation = "Horizontal" Background = "LightSkyBlue" Grid.Row = "2">
<GroupBox x:Name = "groupBox2" Header = "AB Deployed Reader" Width = "778" Height = "200" Margin = "10,-20,10,14">
<StackPanel >
<Label x:Name = "lbABDeployed" Content = "{Binding lblABDeployed}" HorizontalAlignment = "Left" Margin = "10,8,0,0" VerticalAlignment = "Top" Height = "125" Width = "743"/>
<Button x:Name = "btnStartABDeployedReader" Content = "{Binding sStart}" Command = "{Binding btnStartABDeployedReader}" HorizontalAlignment = "Left" Margin = "10,13,0,15" VerticalAlignment = "Center" Height = "20" Width = "50"/>
<Button x:Name = "btnOpenOutput" Command = "{Binding btnOpenOutput}" Content = "Open output file" Height = "20" Width = "100" Margin = "-502,-35,0,15" VerticalAlignment = "Center"/>
<CheckBox x:Name = "chkBSingle" Content = "Single application configuration" IsChecked = "{Binding IschkBSingle}" IsEnabled = "{Binding IsProcessingData}" Margin = "196,-33,0,0" Width = "198" HorizontalAlignment = "Left" VerticalAlignment = "Top" Height = "24"/>
</StackPanel>
</GroupBox>
</StackPanel>
<StackPanel Orientation = "Horizontal" Background = "LightCyan" Grid.Row = "3">
<CheckBox x:Name = "chkBClearLog" Content = "Clear error log" IsChecked = "{Binding IschkBClearLog}" IsEnabled = "{Binding IsProcessingData}" HorizontalAlignment = "Left" Margin = "10,14,0,0" VerticalAlignment = "Top"/>
<RadioButton GroupName = "btnErrorLog" Command = "{Binding btnErrorLog}" Content = "{Binding ErrorText}" Width = "80"
Margin = "32,-25,5,5" VerticalAlignment = "Center" Style = "{StaticResource GroupToggleStyle}" Height = "20" IsEnabled = "{Binding IsError}"/>
<Label x:Name = "lblVersion" Content = "{Binding lblVersion}" HorizontalAlignment = "Left" Margin = "-210,39,0,0" VerticalAlignment = "Top"/>
<!--<Button x:Name = "btnError" Content = "Error Log" Command = "{Binding btnErrorLog}" HorizontalAlignment = "Left" Margin = "-92,43,0,0" VerticalAlignment = "Top" Height = "20" Width = "50"/>-->
</StackPanel>
</Grid>
</Window>
Моя MainWindowViewModel: (ни одна ViewModel еще не создана полностью в MVVM, используя CommunityToolkit.Mvvm). Частичный код для уменьшения объема данных.
namespace XPR_AppBuilderSuiteWpf
{
public partial class MainWindowViewModel : ObservableRecipient
{
#region Variables/Fields
private string _txtBFilter;
private string _txtBResult;
private string _txtBStatus;
private string _lblVersion;
private string _lblABDeployed;
private bool _ischkBCallflowXML;
private bool _ischkBWorkspaceXML;
private bool _ischkBAppXML;
private bool _ischkBVariablesXML;
private bool _ischkBDontAddFilename;
private bool _ischkBSingle;
private bool _ischkBClearLog;
private bool _isError;//enables the button to be clicked on else it is not enabled.
private bool _isErrorProcess;//use to set the error button color.
private bool _isProcessingData;//to enable or disable the checkboxes, buttons or other controls
private string _sSelectXMLFile = string.Empty;
private string _sFindTags = string.Empty;
private string _sSelectFolder = string.Empty;
private string _sStart = string.Empty;
#endregion
#region RelayCommands
//aka buttons or "Commands = {Binding...}"
public AsyncRelayCommand btnSelectXMLFile { get; set; }
public AsyncRelayCommand btnFindTags { get; set; }
public AsyncRelayCommand btnSelectFolder { get; set; }
public AsyncRelayCommand btnStartABDeployedReader { get; set; }
public AsyncRelayCommand btnOpenOutput { get; set; }
public AsyncRelayCommand btnErrorLog { get; set; }
#endregion
#region Properties
//aka textboxes, checkboxes, listboxes etc
public bool IschkBCallflowXML
{
get => _ischkBCallflowXML;
set
{
if (_ischkBCallflowXML == value)
return;
_ischkBCallflowXML = value;
OnPropertyChanged(nameof(IschkBCallflowXML));
}
}
public bool IschkBWorkspaceXML
{
get => _ischkBWorkspaceXML;
set
{
if (_ischkBWorkspaceXML == value)
return;
_ischkBWorkspaceXML = value;
OnPropertyChanged(nameof(IschkBWorkspaceXML));
}
}
public bool IschkBAppXML
{
get => _ischkBAppXML;
set
{
if (_ischkBAppXML == value)
return;
_ischkBAppXML = value;
OnPropertyChanged(nameof(IschkBAppXML));
}
}
public bool IschkBVariablesXML
{
get => _ischkBVariablesXML;
set
{
if (_ischkBVariablesXML == value)
return;
_ischkBVariablesXML = value;
OnPropertyChanged(nameof(IschkBVariablesXML));
}
}
public bool IschkBDontAddFilename
{
get => _ischkBDontAddFilename;
set
{
if (_ischkBDontAddFilename == value)
return;
_ischkBDontAddFilename = value;
OnPropertyChanged(nameof(IschkBDontAddFilename));
}
}
public string txtBFilter
{
get => _txtBFilter;
set
{
if (_txtBFilter == value)
return;
_txtBFilter = value;
OnPropertyChanged(nameof(txtBFilter));
}
}
public string txtBResult
{
get => _txtBResult;
set
{
if (_txtBResult == value)
return;
_txtBResult = value;
OnPropertyChanged(nameof(txtBResult));
}
}
public string txtBStatus
{
get => _txtBStatus;
set
{
if (_txtBStatus == value)
return;
_txtBStatus = value;
OnPropertyChanged(nameof(txtBStatus));
}
}
public string lblABDeployed
{
get => _lblABDeployed;
set
{
if (_lblABDeployed == value)
return;
_lblABDeployed = value;
OnPropertyChanged(nameof(lblABDeployed));
}
}
public bool IschkBSingle
{
get => _ischkBSingle;
set
{
if (_ischkBSingle == value)
return;
_ischkBSingle = value;
OnPropertyChanged(nameof(IschkBSingle));
}
}
public bool IschkBClearLog
{
get => _ischkBClearLog;
set
{
if (_ischkBClearLog == value)
return;
_ischkBClearLog = value;
OnPropertyChanged(nameof(IschkBClearLog));
}
}
public bool IsProcessingData
{
get => _isProcessingData;
set
{
if (_isProcessingData == value)
return;
_isProcessingData = value;
OnPropertyChanged(nameof(IsProcessingData));
}
}
public string lblVersion
{
get => _lblVersion;
set
{
if (_lblVersion == value)
return;
_lblVersion = value;
OnPropertyChanged(nameof(lblVersion));
}
}
public bool IsError
{
get => _isError;
set
{
if (_isError == value)
return;
_isError = value;
OnPropertyChanged(nameof(IsError));
}
}
public bool IsErrorProcess
{
get => _isErrorProcess;
set
{
if (_isErrorProcess == value)
return;
_isErrorProcess = value;
OnPropertyChanged(nameof(IsErrorProcess));
}
}
public string sSelectXMLFile
{
get => _sSelectXMLFile;
set
{
if (_sSelectXMLFile == value)
return;
_sSelectXMLFile = value;
OnPropertyChanged(nameof(sSelectXMLFile));
}
}
public string sFindTags
{
get => _sFindTags;
set
{
if (_sFindTags == value)
return;
_sFindTags = value;
OnPropertyChanged(nameof(sFindTags));
}
}
public string sSelectFolder
{
get => _sSelectFolder;
set
{
if (_sSelectFolder == value)
return;
_sFindTags = value;
OnPropertyChanged(nameof(sSelectFolder));
}
}
public string sStart
{
get => _sStart;
set
{
if (_sStart == value)
return;
_sFindTags = value;
OnPropertyChanged(nameof(sStart));
}
}
//End of declarations.
//https://stackoverflow.com/questions/76871709/using-mvvm-communitytoolkit-to-change-button-foreground-or-background
[ObservableProperty]
private string? errorText;
#endregion
public MainWindowViewModel()
{
txtBFilter = string.Empty;
txtBResult = string.Empty;
txtBStatus = string.Empty;
lblVersion = string.Empty;
lblABDeployed = string.Empty;
ErrorText = "Error Log";
IsError = false;
IsProcessingData = true;//to enable or disable the checkboxes, buttons or other controls
_sSelectXMLFile = "Select a XML";
_sFindTags = "Find Tags";
_sSelectFolder = "Select Folder";
_sStart = "Start";
string sTemp = System.Reflection.Assembly.GetEntryAssembly().FullName;
Globals.sApplicationName = sTemp.Substring(0, sTemp.IndexOf(","));
Globals.sEFApplicationName = sTemp.Substring(0, sTemp.IndexOf(","));
string[] aSplit = sTemp.Split(',');
lblVersion = "Version: " + aSplit[0] + " " + aSplit[1];
#region Button initialization
btnSelectXMLFile = new AsyncRelayCommand(OnbtnSelectXMLFileExecute, () => true);
btnFindTags = new AsyncRelayCommand(OnbtnFindTagsExecute, () => true);
btnSelectFolder = new AsyncRelayCommand(OnbtnSelectFolderExecute, () => true);
btnOpenOutput = new AsyncRelayCommand(OnbtnOpenOutputExecute, () => true);
btnStartABDeployedReader = new AsyncRelayCommand(OnbtnStartABDeployedReaderExecute, () => true);
btnErrorLog = new AsyncRelayCommand(OnbtnErrorLogExecute, () => true);
lblABDeployed = "This program will read an Xpressions correl or full export file.\n\r" +
"Then create an Excel workbook in the folder the DB was specified.\n\r" +
"All header values/names are those of AppBuilder as seen when deployed and written to the correl.";
// Register a message in some module
WeakReferenceMessenger.Default.Register<StatusMessages>(this, (r, m) =>
{
// Handle the message here, with r being the recipient and m being the
// input message. Using the recipient passed as input makes it so that
// the lambda expression doesn't capture "this", improving performance.
UpdateStatusMessage(m.Value);
});
#endregion
}
private async Task OnbtnSelectXMLFileExecute()
{
if (IschkBClearLog == true)
ClearErrorLog();
string sHold = _sSelectXMLFile, sResult = string.Empty;
_sSelectXMLFile = "Running...";
OpenFileDialog openFile = new OpenFileDialog();
openFile.Multiselect = true;
openFile.Title = "Select Application Builder XML file(s)"; //!!sets the dialog box title!!
openFile.FileName = null;
openFile.DefaultExt = "xml";
openFile.Filter = "AppBuilder (*.xml)|*.xml|All files (*.*)|*.*";
if (openFile.ShowDialog() == true)//if not true then it is cancel so skip
{
WeakReferenceMessenger.Default.Send(new StatusMessages($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} - Starting XML file processing."));
ErrorFile.WriteError("======SelectXMLFile==== = ", "", 0);
IsErrorProcess = false;
await Task.Run(() =>
{
sResult = ReadABXMLTasks.SeletXMLFileTask(IschkBDontAddFilename, openFile, IschkBCallflowXML, IschkBAppXML, IschkBVariablesXML,
IschkBWorkspaceXML);
});
//Work on this button click does not work
if (Globals.bErrorOn == true)
{
IsErrorProcess = IsErrorProcess is true;
IsError = true;
}
}
_sSelectXMLFile = sHold;
txtBResult = sResult;
}
Надеюсь, этого кода достаточно. Опять же, я новичок в WPF. Показан код для кнопки «btnSelectXMLFile». Я надеюсь включить вашу помощь в работу с другими кнопками, а затем и в будущий проект.
«Надеюсь, этого кода достаточно» — это слишком много. Пожалуйста, опубликуйте соответствующие части вашего кода, а не весь.
Ваша проблема в том, что вы меняете поле в OnbtnSelectXMLFileExecute().
_sSelectXMLFile = "Running...";
Вместо собственности
sSelectXMLFile = "Running...";
Это предотвращает запуск события NotifyPropertyChanged. И без запуска события пользовательский интерфейс не обновляется.
Спасибо, я думал, что уже это сделал.
«Контекст» или «Содержание»?