wpf MVVM 中的绑定滑块值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14339515/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 07:02:10  来源:igfitidea点击:

binding slider value in MVVM

wpfmvvmbindingslider

提问by Hamid Fara

I have a problem in slider value data binding in MVVM. When value gets changed my expected value isn't achieved. How can I solve my problem?
I have a listbox, a slider and a textblock. listbox is bound to ListImage, slider value and textblock text is bound to CurrentImage. One button with command navigate the lisbox item. CurrentImage is a property in the viewmodel. When I change slider's setter, new value of setter put to current value of slider's setter and the arrangement of listbox gets corrupted. For example when value of my slider's setter set to 50 and I change value of slider to 10 again. My slider value navigate from 10 to 50 and not more. It must be navigate whole of the listbox but it can't. There is my code:

我在 MVVM 中的滑块值数据绑定有问题。当价值改变时,我的预期价值没有达到。我该如何解决我的问题?
我有一个列表框、一个滑块和一个文本块。listbox 绑定到 ListImage,滑块值和 textblock 文本绑定到 CurrentImage。一个带有命令的按钮导航 lisbox 项目。CurrentImage 是视图模型中的一个属性。当我更改滑块的 setter 时,setter 的新值会变为滑块 setter 的当前值,并且列表框的排列会被破坏。例如,当我的滑块设置器的值设置为 50 并且我再次将滑块的值更改为 10 时。我的滑块值从 10 导航到 50 而不是更多。它必须导航整个列表框,但不能。有我的代码:

XAML:

XAML:

<TextBlock Text="{Binding CurrentImage.Index}"/>
<Slider Height="23" HorizontalAlignment="Left" Margin="12,305,0,0" Name="slider1" VerticalAlignment="Top" Width="479" Maximum="{Binding ListImage.Count, Mode=OneTime}"
              Value="{Binding CurrentImage.Index, Mode=TwoWay}"
              SmallChange="1" />
<Button Content="{Binding DisplayPlay}" Command="{Binding PlayCommand}" Height="23" HorizontalAlignment="Left" Margin="507,305,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
<ListBox Height="129" HorizontalAlignment="Left"  Margin="12,334,0,0" ItemsSource="{Binding ListImage}" SelectedItem="{Binding CurrentImage,Mode=TwoWay}" 
                 VerticalAlignment="Top" Width="472">

viewmodel:

视图模型:

public class MainViewModel : ViewModelBase
{
    public ICommand PlayCommand { get; set; }
    private DispatcherTimer _Timer;
    public ImageDTO Image { get; set;}
    DataAccess AC = new DataAccess();
    public byte[] Bytes { get; set; }
    public MainViewModel()
    {
        ListImage = AC.OpenImages();
        CurrentImage = ListImage[0];
        Bytes = CurrentImage.Bytes;
        this.PlayCommand = new DelegateCommand(Play, CanPlay);
        DisplayPlay = "Play";
        _Timer = new DispatcherTimer();
        _Timer.Interval = new TimeSpan(0, 0, 0, 0, 2000 / 30);
        _Timer.Tick += new EventHandler(timer_Tick);
    }

    private string _DisplayPlay;
    public string DisplayPlay
    {
        get { return _DisplayPlay; }
        set
        {
            if (_DisplayPlay != value)
            {
                _DisplayPlay = value;
                OnPropertyChanged("DisplayPlay");
            }
        }
    }

    private List<ImageDTO> _ListImage;
    public List<ImageDTO> ListImage
    {
        get { return _ListImage; }
        set
        {
            if (_ListImage != value)
                _ListImage = value;
                OnPropertyChanged("ListImage");
        }
    }

    private ImageDTO _CurrentImage;
    public ImageDTO CurrentImage
    {
        get { return _CurrentImage; }
        set
        {
            if (_CurrentImage != value)
            {
                _CurrentImage = value;
                OnPropertyChanged("CurrentImage");
            }
        }
    }

    public bool CanPlay(object parameter)
    {
        return true;
    }
    public void Play(object parameter)
    {
        if (DisplayPlay == "Play")
        {
            DisplayPlay = "Pause";
            _Timer.Start();
        }
        else
        {
            _Timer.Stop();
            DisplayPlay = "Play";
        }
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        int position = ListImage.FindIndex(x => x.Index == CurrentImage.Index);
        position++;
        if (position == ListImage.Count)
        {
            position = 0;
        }
        else
        {
            CurrentImage = ListImage[position];
        }
    }

回答by Johan Larsson

Maybe this is what you want:

也许这就是你想要的:

<StackPanel>
    <ListBox x:Name="ImageListBox" IsSynchronizedWithCurrentItem="True">
        <ListBoxItem>Image1</ListBoxItem>
        <ListBoxItem>Image2</ListBoxItem>
        <ListBoxItem>Image3</ListBoxItem>
        <ListBoxItem>Image4</ListBoxItem>
    </ListBox>
    <Slider Value="{Binding ElementName=ImageListBox, Path=SelectedIndex}" 
            Maximum="{Binding ElementName=ImageListBox, Path=Items.Count}"/>
</StackPanel>

You probably want to handle the max value nicer than in this sample

您可能希望比在此示例中更好地处理最大值

回答by Fred Jand

In your code the value of slider is bound to CurrentImage index, so when you change the value of slider then the index of the current image will be changed. Assumed that the current image index is 5 then your slider's value will be 5 then if you move the slider pointer to a position like 10 then the Current image index will be set to 10 it means that your current image will be modified, so it means that it would not navigate to the 10th element of list, but it modifies the index of the image (with index of 5) and set its index to 10, in other words, you would not have a image with index of 5 anymore and 2 of your images are going to have the same index (10).

在您的代码中,滑块的值绑定到 CurrentImage 索引,因此当您更改滑块的值时,当前图像的索引将更改。假设当前图像索引是 5 那么你的滑块的值将是 5 那么如果你将滑块指针移动到一个像 10 这样的位置那么当前图像索引将被设置为 10 这意味着你的当前图像将被修改,所以这意味着它不会导航到列表的第 10 个元素,但它会修改图像的索引(索引为 5)并将其索引设置为 10,换句话说,您将不再拥有索引为 5 的图像和 2的图像将具有相同的索引 (10)。

As a solution, you can add another property like “Index” into your viewmodel, and bind the slider value to that one, so at get method return the index of the selected item in list, and at the set method change the selected item in the list and call OnPropertyChanged and pass “Index” as the parameter.

作为解决方案,您可以在视图模型中添加另一个属性,例如“索引”,并将滑块值绑定到该值,因此在 get 方法返回列表中所选项目的索引,并在 set 方法中更改所选项目列表并调用 OnPropertyChanged 并传递“Index”作为参数。