WPF-те батырманы қалай қосуға/ажыратуға болады?

Менде қарапайым wpf қосымшасы бар. Идея пайдаланушылардың тізімін ұсыну болып табылады; әрбір элемент үшін элементті таңдау/бөлектеу үшін құсбелгі бар.

Менің кодым жеңілдетілді, келесідей көрінеді:

 class Thing { /* ... */ };
 public static int SelectedCount { get; set; }
 public class SelectableThing
 {
        private bool _selected;
        public bool Selected { 
            get { return _selected; }
            set { _selected = value; if (value) { SelectedCount++; } else { SelectedCount--; } } 
        }
        public Thing thing { get; set; }
 };
 private ObservableCollection _selectableThings;
 public Collection { get { return _selectableThings; } }
 
      
      
 
 <button Content="{Binding Path=SelectedTestCount}" Click="someFunc" />

Мәселен, түйме мазмұны таңдалған сынақтардың санын көрсетуі керек. Бұл таңдау орындалуы керек, себебі SelectableThing.Selected таңдалған болса, ол сәйкесінше SelectedCount мәнін ұлғайтуға/азайтуға тиіс.

Дегенмен, мінез-құлықтың жұмыс істемейтінін айта аламын. Түймешік мәтіні тізімдегі элементтерді таңдау/таңдаудан бөлек қарамастан, «0» көрсетеді.

Кез келген идеялар?

3
Көру модельдерін қолданамын.
қосылды автор Stephen Gross, көзі
Көру модемдерін немесе жай-кодты пайдаланасыз ба?
қосылды автор Yatrix, көзі

2 жауаптар

Бұл проблема сізде бірнеше модель сабақтары бар болғандықтан, сәл күлгін болып табылады. Міне, осы мәселені шешу үшін кодтың жарылуы. Мен жоғалтқан жалғыз нәрсе - бұл сізден шықпайынша DataGrid сіздің элементтеріңізді жаңартпайды.

At start, before any edits. The save button is disabled, and the count is zero After some edits. The save button is enabled, and the count is updated

XAML:


    
        
            
            
        
        
            
                
                
            
        
        <button Content="{Binding Path=SelectedTestCount}"
                Command="{Binding SaveCommand}"
                Grid.Row="1" Width="75" Height="23"
                HorizontalAlignment="Right" Margin="0,0,6,6"/>
    

Сынып сыныптары:

public class Thing : INotifyPropertyChanged
{
    private readonly List selectableThings;
    private DelegateCommand saveCommand;

    public Thing(IEnumerable selectableThings)
    {
        this.selectableThings = new List(selectableThings);
        this.SelectableThings =
            new ObservableCollection(this.selectableThings);

        this.SaveCommand = this.saveCommand = new DelegateCommand(
            o => Save(),
            o => SelectableThings.Any(t => t.IsSelected)
            );

       //Bind children to change event
        foreach (var selectableThing in this.selectableThings)
        {
            selectableThing.PropertyChanged += SelectableThingChanged;
        }

        SelectableThings.CollectionChanged += SelectableThingsChanged;
    }

    public ObservableCollection SelectableThings
    {
        get;
        private set;
    }

    public int SelectedTestCount
    {
        get { return SelectableThings.Where(t => t.IsSelected).Count(); }
    }

    public ICommand SaveCommand { get; private set; }

    private void Save()
    {
       //Todo: Implement
    }

    private void SelectableThingChanged(object sender,
        PropertyChangedEventArgs args)
    {
        if (args.PropertyName == "IsSelected")
        {
            RaisePropertyChanged("SelectedTestCount");
            saveCommand.RaiseCanExecuteChanged();
        }
    }

    private void SelectableThingsChanged(object sender,
        NotifyCollectionChangedEventArgs e)
    {
        foreach (SelectableThing selectableThing in
            e.OldItems ?? new List())
        {
            selectableThing.PropertyChanged -= SelectableThingChanged;
            RaisePropertyChanged("SelectedTestCount");
        }

        foreach (SelectableThing selectableThing in
            e.NewItems ?? new List())
        {
            selectableThing.PropertyChanged += SelectableThingChanged;
            RaisePropertyChanged("SelectedTestCount");
        }
    }

    public void RaisePropertyChanged(string propertyName)
    {
        if(PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

SelectableСынып сыныптары:

public class SelectableThing : INotifyPropertyChanged
{
    private string name;
    private bool isSelected;

    public SelectableThing(string name)
    {
        this.name = name;
    }

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            RaisePropertyChanged("Name");
        }
    }

    public bool IsSelected
    {
        get { return isSelected; }
        set
        {
            isSelected = value;
            RaisePropertyChanged("IsSelected");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Оригинал жауап:

Command кодын ICommand -қа қосыңыз. Сіздің жағдайыңыз қанағаттандырылмаған кезде false қайтару үшін ICommand CanExecute параметрін орнатыңыз.

IsSelected сипаты үшін қондырғыда, мән өзгергенде, CanExecuteChanged оқиғасын көтеріңіз.

CanExecute нәтижесінің негізінде Command байланысы Button -да автоматты түрде қосылады/өшіреді.

Бұл әрекетті қалай жасау керектігі туралы қосымша ақпарат алу үшін, мұнда қолдануға болатын ICommand енгізілуін қоса, қараңыз this mini-MVVM tutorial Мен басқа сұраққа жаздым.

CanExecute енгізу жолын толтыру үшін Linq's . . әдісін қолданамын. Одан кейін Count тексеруін тоқтатуға тура келмейді және кез-келген элементтің тексерілгенін білсеңіз, циклды ертерек тоқтата аласыз.

Мысалға:

this.SaveCommand = new DelegateCommand(Save, CanSave);

// ...

private void Save(object unusedArg)
{
   //Todo: Implement
}

private bool CanSave(object unusedArg)
{
    return SelectableThings.Any(t => t.IsSelected);
}

Немесе қысқа болғандықтан, lambda кірістіруін пайдаланыңыз:

this.SaveCommand = new DelegateCommand(Save,
    o => SelectableThings.Any(t => t.IsSelected)
    );
3
қосылды
IsSelected өзгеруіне байланысты CanExecuteChanged деңгейін көтеру туралы бит қиын болуы мүмкін, себебі сіз бала көрінісі үлгілерінің жиынтығын пайдаланасыз. Сіз әрқайсысына INotifyPropertyChanged жазылсаңыз болады және оқиғаны this.SaveCommand.RaiseCanExecuteChanged() жіберіңіз. Сізге бұл бөлікті анықтайтын қиындықтар бар ма?
қосылды автор Merlyn Morgan-Graham, көзі
Сондай-ақ, IsSelected сипатын атаңыз деп ұсынамын. Логикалық мәндерді (Is, Can, Has, және т.б.) атау кезінде осы конвенцияны орындау керек.
қосылды автор Merlyn Morgan-Graham, көзі
@StephenGross: static пайдаланған кезде жұмыс істей алады, бұл бұзу. Сіз бұл сипатты ( Thing ?) Сыныпты ұстап тұрған бірнеше даналарын қолдай алмадыңыз. Бұл код үшін бірлік сынақтарын жазу қиын болады. Мен де wpf статикалық сипаттарға байланса немесе болмаса, немесе INotifyPropertyChanged жұмыс істейтініне сенімді емеспін.
қосылды автор Merlyn Morgan-Graham, көзі
@Stephen: Мен нені айтқым келетінін көрсету үшін бірнеше кодты енгіздім, себебі бұл мәселе жаман емес. Менің шешімім сіз үшін INotifyPropertyChanged материалдарының кейбірін орындайтын құралдарды пайдаланбастан, таза күйге жету үшін жақын болады.
қосылды автор Merlyn Morgan-Graham, көзі
@Stephen: Мәселе мынада, бірде-бір құсбелгі өзгерсе, сізге/мәтін жолағын жаңарту керек. Мұны жалғыз тәсіл - барлық оқиғаларға жазылу. wpf оқиғаға арналған құсбелгіге жазылады, бірақ жиынтықтағы барлық оқиғаларға жазылудың қарапайым жолы жоқ. Сіз оны шешу үшін құсбелгілерде тырнақшаны қолданып көруіңіз мүмкін, бірақ бұл жұмыс үшін жұмыс істеу үшін кейбір back-end конвертерінің кодын қажет болуы мүмкін (бұл жауапты орындаған Linq-ге ұқсас бағдарламалармен).
қосылды автор Merlyn Morgan-Graham, көзі
@Stephen: Егер оны сіз ұсынатыннан өзгеше әдіспен жұмыс істесем, оны бөлек жауап ретінде қосуды және оны қабылдауды ұсынамын.
қосылды автор Merlyn Morgan-Graham, көзі
Мен сіздердің енгізулеріңізді көрсету үшін бастапқы сұрақты өзгерттім; Сіз маған өз ойларыңызды білуге ​​рұқсат ете аласыз ба?
қосылды автор Stephen Gross, көзі
Иә, мен статикалық int қолданған жалғыз себебі - оны SelectableThing.Selected.set() ішінен өзгерту мүмкін емес.
қосылды автор Stephen Gross, көзі
Жақсы, мен сіздің түзетілген ұсыныстарыңызды қарап жатырмын. Қарапайым тәсілі болуы керек сияқты ... Егер IsleScached логикалық өзгерген сайын, орнатылған int inte SelectedCount төлсипаты болуы мүмкін емес пе? Егер солай болса, онда мен SelectedCount-ге бақылауды байланыстырып, оларды сол жолмен басқаруға мүмкіндігім болуы керек.
қосылды автор Stephen Gross, көзі

Түймешік мазмұнын өзіңіздің қарау үлгісінің өрісіне байланыстырыңыз және әр элементтің таңдалған немесе таңдалмаған сайын осы өріске арналған OnChanged әдісін өртемеңіз. IsEnabled-ді көру үлгісіндегі логикалық өріске байлаңыз және түймешікті қосу немесе өшіру үшін оны сәйкесінше true/false деп орнатыңыз.

1
қосылды
Мен бұл сұрақты сынап көру үшін бастапқы сұрақты өзгертіп қойдым, бірақ дұрыс емес (!) ...
қосылды автор Stephen Gross, көзі