更改按钮内容MVVM

时间:2018-04-27 17:48:25

标签: c# wpf

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

 <StackPanel Orientation="Horizontal">

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

我搜索并找到了这个:WPF Button content binding但是当我拥有所有这三个时,我不确定如何应用解决方案: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,基本上删除Text和PackIcon并将ProgressBar放在按钮中。

3 个答案:

答案 0 :(得分:5)

实际上,可以使用数据触发器更改控件;虽然在这种情况下看起来有点过头了。

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

<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>

这将是您按钮的内容。 BooleanToCollapsedConverter只是VisibiltyToBooleanConverter的反转;有很多方法可以做,并留作练习。

撇开; UpdateSourceTrigger对OneWay绑定没有任何意义(它不会更新源!),你甚至不需要可见性,因为这不是用户可以改变的输入。

答案 1 :(得分:1)

您可以使用数据模板。就像是: XAML:

    <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>

C#:

    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 { }

答案 2 :(得分:-1)

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

    <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>

按钮点击的事件将是:

    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
    }

请注意,如果使用MVVM模式,也可以绑定视图模型中属性的Tag属性。