Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/267.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 更改按钮内容MVVM_C#_Wpf - Fatal编程技术网

C# 更改按钮内容MVVM

C# 更改按钮内容MVVM,c#,wpf,C#,Wpf,我有一个包含以下内容的按钮: <StackPanel Orientation="Horizontal"> <TextBlock Text="Connect"/> <materialDesign:PackIcon Kind="Arrow"/> </StackPanel> 我搜索并找到了这个:但我不知道当我有三个:Stackpanel、PackIcon(对象)和Textblo

我有一个包含以下内容的按钮:

 <StackPanel Orientation="Horizontal">

                <TextBlock Text="Connect"/>
                <materialDesign:PackIcon Kind="Arrow"/>
  </StackPanel>

我搜索并找到了这个:但我不知道当我有三个:Stackpanel、PackIcon(对象)和Textblock时,如何应用解决方案

我有一个progressBar,我将它显示在按钮下:

 <ProgressBar  x:Name="XZ" Foreground="Black" Grid.Row="4" Grid.Column="1"
                  Visibility="{Binding Connecting, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
            Value="50"
            IsIndeterminate="True" />


当我点击按钮时,我想这样做,而不是现在显示ProgressBar的位置,基本上删除文本和PackIcon,并将ProgressBar放在按钮中。

实际更改控件可以通过数据触发器来完成;不过在这种情况下,这似乎有点过头了

我只想切换两个控件的可见性:

<Grid>
    <StackPanel Orientation="Horizontal" Visibility="{Binding Connecting, Converter={StaticResource BooleanToCollapsedConverter}}"">

                <TextBlock Text="Connect"/>
                <materialDesign:PackIcon Kind="Arrow"/>
    </StackPanel>
    <ProgressBar  x:Name="XZ" Foreground="Black" Grid.Row="4" Grid.Column="1"
                  Visibility="{Binding Connecting, Converter={StaticResource BooleanToVisibilityConverter}}"
            Value="50"
            IsIndeterminate="True" />
</Grid>


您可以为按钮创建一个模板来实现这一点,然后在需要加载按钮的任何地方重用该模板,如下所示:

    <Button Width="120" Height="40" Tag="False" Name="loadingButton" Click="loadingButton_Click">
    <Button.Template>
        <ControlTemplate>
            <Border Name="PART_Border" BorderBrush="Black" BorderThickness="1" CornerRadius="2" Background="Transparent">
                <Grid Name="PART_Root">
                    <TextBlock Name="PART_Text" HorizontalAlignment="Center" VerticalAlignment="Center">Data</TextBlock>
                    <ProgressBar  IsIndeterminate="True"  Name="PART_Loading"></ProgressBar>
                </Grid>
            </Border>
            <ControlTemplate.Triggers>
                <Trigger Property="Tag" Value="True">
                    <Setter TargetName="PART_Text" Property="Visibility" Value="Collapsed"></Setter>
                    <Setter TargetName="PART_Loading" Property="Visibility" Value="Visible"></Setter>
                </Trigger>

                <Trigger Property="Tag" Value="False" >
                    <Setter TargetName="PART_Text" Property="Visibility" Value="Visible"></Setter>
                    <Setter TargetName="PART_Loading" Property="Visibility" Value="Collapsed"></Setter>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Button.Template>
</Button>

请注意,如果使用MVVM模式,还可以为视图模型内的属性绑定标记属性。

可以使用数据模板。比如: XAML:


C#:

公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
this.DataContext=新的MainWindowViewModel();
}
}
公共类ViewModelBase:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
[NotifyPropertyChangedInvocator]
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
}
公共类MainWindowViewModel:ViewModelBase
{
公共主窗口视图模型()
{
ButtonInfo=新建ButtonInfo(){Label=“Button Info”};
ProcessCommand=新的DelegateCommand(进程);
}
私人按钮信息(u ButtonInfo);;
公共按钮信息按钮信息
{
获取{return\u buttonInfo;}
设置
{
_按钮信息=值;
OnPropertyChanged();
}
}
公共DelegateCommand ProcessCommand{get;set;}
私有异步无效进程()
{
ButtonInfo=new ProgressInfo(){Label=“ProgressInfo”};
等待ProcessAsync();
}
专用任务ProcessAsync()
{
返回任务。运行(()=>
{
对于(int i=0;i<100;i++)
{
Application.Current.Dispatcher.Invoke(()=>
{
按钮信息进度=i;
如果(i==99)
{
ButtonInfo=新建ButtonInfo(){Label=“Button reach”};
}
});
睡眠(100);
}
});
}
}
公共类按钮信息:ViewModelBase
{
私有字符串标签;
私人互联网进展;
私有布尔处理;
公共字符串标签
{
获取{return\u label;}
设置
{
_标签=值;
OnPropertyChanged();
}
}
公共信息技术进步
{
获取{return\u progress;}
设置
{
_进步=价值;
OnPropertyChanged();
}
}
公共布尔处理
{
获取{return\u isProcessing;}
设置
{
_i处理=值;
OnPropertyChanged();
}
}
}
公共类ProgressInfo:按钮信息{}

使用数据触发器。通常最好在所有内容上放置一个低透明度面板,并在其中显示微调器/忙碌/跳动器。当你这样做的时候,集中注意力。这样,当用户点击任何可能会损坏的东西时,它会阻止用户点击任何东西,并且它完全清楚地表明用户不应该继续操作。所以你是建议我隐藏控件并显示进度条?我不知道我之前怎么没有想到这一点,我觉得自己很愚蠢。我很感激,伙计!thanks@BradleyDotNet,我可以问一下为什么你会在
数据模板
@BradleyDotNet上使用
触发器
,所以我读到的是,我所做的并不是不正确的,只是有点过火了?@3xGuy在我看来;是的,这似乎太过分了。扩展您的概念意味着您可以为程序中UI控件的每个可能状态创建类。很难很快管理好。我所做的或一个数据触发器似乎是正确的答案me@BradleyDotNet,谢谢,因为我在这里的回答是为了变得更好,并尝试将我的答案与其他答案进行比较。谢谢你的意见。看起来DataTrigger比滥用这样的标记要好。使用这样的模板似乎是合理的,但我认为标记不是最好的属性。可能是具有附加属性的派生用户控件?(例如,称为
StatefulButton
)我通常会这样做,创建自定义控件或至少是用户控件,但如果不使用标记,则更容易理解WPFMaybe中的新成员,并将其应用于WPFMaybe isenabled将是一个好主意。如果此进程运行时未禁用此按钮,那么如果用户再次单击该按钮,会发生什么情况?通常情况下,那会是件坏事。
    private async void loadingButton_Click(object sender, RoutedEventArgs e)
    {
        loadingButton.Tag = true.ToString();//display loading
        await Task.Run(() => { Thread.Sleep(4000); });//fake data loading
        loadingButton.Tag = false.ToString();//hide loading
    }
    <Window.Resources>
    <DataTemplate DataType="{x:Type local:ButtonInfo}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <Label Grid.Row="0" Content="Press me"></Label>
            <Label Grid.Row="1" Content="{Binding Label}"></Label>
        </Grid>
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:ProgressInfo}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <ProgressBar Height="30" Value="{Binding Progress}"></ProgressBar>
            <Label Grid.Row="1" Content="{Binding Label}"></Label>
        </Grid>
    </DataTemplate>
</Window.Resources>


   <Grid>
        <Button Command="{Binding ProcessCommand}" Content="{Binding ButtonInfo}">            
        </Button>
    </Grid>
    public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new MainWindowViewModel();
    }
}

public class ViewModelBase:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class MainWindowViewModel:ViewModelBase
{
    public MainWindowViewModel()
    {
        ButtonInfo = new ButtonInfo(){Label = "Button Info"};
        ProcessCommand = new DelegateCommand(Process);
    }
    private ButtonInfo _buttonInfo;
    public ButtonInfo ButtonInfo
    {
        get { return _buttonInfo; }
        set
        {
            _buttonInfo = value;
            OnPropertyChanged();
        }
    }

    public DelegateCommand ProcessCommand { get; set; }

    private async void Process()
    {
        ButtonInfo = new ProgressInfo(){Label = "Progress Info"};
        await ProcessAsync();
    }

    private Task ProcessAsync()
    {
        return Task.Run(() =>
        {
            for (int i = 0; i < 100; i++)
            {
                Application.Current.Dispatcher.Invoke(() =>
                {
                    ButtonInfo.Progress = i;
                    if (i==99)
                    {
                        ButtonInfo = new ButtonInfo(){Label = "Button Again"};
                    }
                });
                Thread.Sleep(100);
            }
        });
    }
}

public class ButtonInfo:ViewModelBase
{
    private string _label;
    private int _progress;
    private bool _isProcessing;

    public string Label
    {
        get { return _label; }
        set
        {
            _label = value;
            OnPropertyChanged();
        }
    }

    public int Progress
    {
        get { return _progress; }
        set
        {
            _progress = value;
            OnPropertyChanged();
        }
    }

    public bool IsProcessing
    {
        get { return _isProcessing; }
        set
        {
            _isProcessing = value;
            OnPropertyChanged();
        }
    }
}

public class ProgressInfo : ButtonInfo { }