Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

WPF MVVM - View Model Properties called more than once

  •  07-02-2011, 19:18

    WPF MVVM - View Model Properties called more than once

    Καλησπέρα σε όλους, 

    προσπαθώ να φτιάξω μια μικρή εφαρμογή σε wpf με το Pattern mvvm. 
    Στο data layer για βάση δεδομένων χρησιμοποιώ .sdf file και Entity Framework.

    H εφαρμογή έχει 3 views και ενα ViewModel

    Στο dataContext του mainWindow κάνω bind το ViewModel και τα άλλα δυο userControls παίζουν με το ίδιο ViewModel.
    Σε ένα UserControl έχω ένα property με όνομα isValid το οποίο  το ενημερώνω  απο το mainWindow.xaml.cs.
    Το πρόβλημα είναι οτι ενώ το property ενημερώνετε σωστά, για κάποιο λόγο γίνεται συνέχεια initialize με αποτέλεσμα να φέρνει πάντα την default τιμή (false δηλαδή).
    Αυτό συμβαίνει στο AddItemsView.xaml

    PLEASE!!!!!!!!! HELP!!!!!!
    Ευχαριστώ εκ των προτέρων για την οποιαδήποτε βοήθεια

    Παρακάτω είναι ο κώδικας

    MainWindow.xaml
    <Window x:Class="ToDoListTest.Views.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:ToDoListTest.Views" 
            xmlns:ViewModels="clr-namespace:ToDoListTest.ViewModels"     
            xmlns:tb="clr-namespace:Hardcodet.Wpf.TaskbarNotification;assembly=Hardcodet.Wpf.TaskbarNotification"
            Title="MainWindow" MinHeight="380"  Width="620" Height="300" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" ResizeMode="CanMinimize">
    
        <Window.DataContext>
            <ViewModels:MainWindowViewModel />
        </Window.DataContext>
    
        <DockPanel>
            <tb:TaskbarIcon
          x:Name="MyNotifyIcon"
          IconSource="/Images/Icons/Error.ico"
          ToolTipText="ToDoList" />
            
            <StackPanel DockPanel.Dock="Top">
                <DockPanel>
                    <local:ViewItemsList DockPanel.Dock="Left"></local:ViewItemsList>
                    <local:AddItemsView DockPanel.Dock="Right" BorderBrush="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                </DockPanel>
            </StackPanel>
            <Grid Background="#FFD8D8D8">
                <local:StatusBar DockPanel.Dock="Bottom"></local:StatusBar>
            </Grid>
        </DockPanel>
    
    </Window>
    mainWIndow.xaml.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Threading;
    using Domain;
    using Samples;
    using ToDoListTest.ViewModels;
    
    namespace ToDoListTest.Views {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window {
    
            private readonly HashSet<ValidationError> errors = new HashSet<ValidationError>();
            private Lazy<MainWindowViewModel> viewModel;
    
            public MainWindow() {
                InitializeComponent();
                InitializeValidaton();
                SetInterval();
            }
    
            void InitializeValidaton() {
                viewModel = new Lazy<MainWindowViewModel>();
                Validation.AddErrorHandler(this, ErrorChangedHandler);
            }
    
            private void ErrorChangedHandler(object sender, ValidationErrorEventArgs e) {
                if (e.Action == ValidationErrorEventAction.Added) {
                    errors.Add(e.Error);
                } else {
                    errors.Remove(e.Error);
                }
    
                viewModel.Value.IsValid = !errors.Any();
            }
    
            void SetInterval() {
                var dispatcherTimer = new DispatcherTimer();
                dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
                dispatcherTimer.Interval = new TimeSpan(0, 1, 0);
                dispatcherTimer.Start();
            }
    
            private void dispatcherTimer_Tick(object sender, EventArgs e) {
                try {
                    var unitOfWork = new EFUnitOfWork();
                    var itemRepository = new ItemRepository(new EFRepository<Item>(), unitOfWork);
                    var item = itemRepository.GetActive();
                    if (item != null) {
                        //Update the status
                        item.Status = true;
                        itemRepository.Save();
                        unitOfWork.Save();
                        var balloon = new FancyBalloon();
                        balloon.BalloonText = item.Name;
                        balloon.BalloonDescription = item.Description;
                        //show balloon and close it after 4 seconds
                        MyNotifyIcon.ShowCustomBalloon(balloon, PopupAnimation.Slide, 4000);
                    }
                } catch (Exception ex) {
                    //swallow
                }
            }
        }
    }
    AddItemsView.xaml
    <UserControl 
                 x:Class="ToDoListTest.Views.AddItemsView"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="310" d:DesignWidth="200">
        <Grid Height="312">
            <Grid.RowDefinitions>
                <RowDefinition Height="55" />
                <RowDefinition Height="89" />
                <RowDefinition Height="62" />
                <RowDefinition Height="56" />
                <RowDefinition Height="37*" />
            </Grid.RowDefinitions>
            <Label Content="Name" Height="28" HorizontalAlignment="Left" Margin="12,0,0,0" Name="label1" VerticalAlignment="Top" />
            <Label Content="Description" Height="28" HorizontalAlignment="Left" Margin="12,51,0,0" Name="label2" VerticalAlignment="Top" Grid.RowSpan="2" />
            <TextBox Text="{Binding Path=ActiveItem.Name, Mode=TwoWay,
                UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true,ValidatesOnExceptions=True, NotifyOnValidationError=True}" Height="23" HorizontalAlignment="Left" Margin="12,22,0,0" VerticalAlignment="Top" Width="176" />
            <TextBox Height="56" Text="{Binding Path=ActiveItem.Description, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true}" HorizontalAlignment="Left" Margin="12,22,0,0" VerticalAlignment="Top" Width="176" TextWrapping="Wrap" Grid.Row="1" />
            <Button Content="Save" Command="{Binding Path=SaveItem}" CommandParameter="{Binding}" Height="25" HorizontalAlignment="Left" Margin="113,14,0,0" Name="button1" VerticalAlignment="Top" Width="75" Grid.Row="4" />
            <Label Content="Date to act" Height="28" HorizontalAlignment="Left" Margin="12,0,0,0" Name="label4" VerticalAlignment="Top" Grid.Row="2" />
            <DatePicker SelectedDate="{Binding Path=ActiveItem.DateToAct, Mode=TwoWay}" Height="25" HorizontalAlignment="Left" Margin="12,0,0,5" Name="datePicker1" VerticalAlignment="Bottom" Width="176" Grid.Row="2" />
            <Label Content="Time to act" Height="28" HorizontalAlignment="Left" Margin="14,0,0,0" Name="label3" VerticalAlignment="Top" Grid.Row="3" />
            <ComboBox Grid.Row="3" SelectedItem="{Binding Path=ActiveItem.Hour}" ItemsSource="{Binding Path=Hours}" DisplayMemberPath="" Height="23" HorizontalAlignment="Left" Margin="14,23,0,0" Name="hourDDL" VerticalAlignment="Top" Width="40" />
            <ComboBox Grid.Row="3" SelectedItem="{Binding Path=ActiveItem.Minute}"  ItemsSource="{Binding Path=Minutes}" Height="23" HorizontalAlignment="Right" Margin="0,23,100,0" Name="minuteDDL" VerticalAlignment="Top" Width="40" />
        </Grid>
    </UserControl>
    AddItemsView.xaml.cs
    using System;
    using System.Windows.Controls;
    using ToDoListTest.ViewModels;
    
    namespace ToDoListTest.Views {
        /// <summary>
        /// Interaction logic for AddItemsView.xaml
        /// </summary>
        public partial class AddItemsView : UserControl {
    
            public AddItemsView() {
                InitializeComponent();
            }
        }
    }
    MainWindowViewModel.cs
    Με κόκκινο είναι η μέθοδος που γίνεται συνέχεια initialize
    using System;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows.Controls.Primitives;
    using System.Windows.Input;
    using System.Windows.Threading;
    using Domain.Infrastructure;
    using Samples;
    using Domain;
    using System.Collections.ObjectModel;
    using ToDoListTest.Services;
    using System.Collections.Generic;
    using System.Waf.Applications;
    
    namespace ToDoListTest.ViewModels {
        public class MainWindowViewModel : ObservableObject {
    
            #region Declarations
            readonly IDialogService _dialog;
            #endregion
    
            #region Properties
             
          ......
    
            private bool _isValid;
            public bool IsValid {
                get { return _isValid; }
                set {
                    _isValid = value;
                    RaisePropertyChanged("IsValid");
                }
            }
          
            
            #endregion
    
            #region Constructors
    
            public MainWindowViewModel() : this(new ModalDialogService()) { }
    
            public MainWindowViewModel(IDialogService dialog) {
                this._dialog = dialog;
                ItemResults = new ObservableCollection<Item>();
                ShowNewItemForm = "Hidden";
                Status = "Ready";
                LoadItemResults();
                PrepareHoursAndMinutes();
            }
            #endregion
    
            #region Commands
            public ICommand AddNewItem {
                get { return new RelayCommand(AddNewItemExecute); }
            }
    
            public ICommand SaveItem {
                get { return new RelayCommand(SaveItemExecute,CanSaveItem); }
            }
    
          .........
    
            #endregion
    
            #region Methods
    
            public void SaveItemExecute() {
                if (ActiveItem == null) {
                    _dialog.ShowMessage("Please select an item from the list to update it, or click the {New} button to create a new item.", "Oops!!", DialogButton.OK, DialogImage.Error);
                    return;
                }
    
                if (ActiveItem.EntityKey != null) {
                    UpdateItem();
                    return;
                }
    
                try {
                    var i = new Item {
                        DateCreated = DateTime.Now,
                        DateToAct = this.ActiveItem.DateToAct,
                        Description = this.ActiveItem.Description,
                        Name = this.ActiveItem.Name,
                        TimeToAct = ActiveItem.TimeToAct,
                        Status = false
                    };
    
                    var unitOfWork = new EFUnitOfWork();
                    var itemRepository = new ItemRepository(new EFRepository<Item>(), unitOfWork);
                    itemRepository.Add(i);
                    unitOfWork.Save();
                    ItemResults.Add(i);
                    ActiveItem = new Item();
                    Status = "Saved!";
                } catch (Exception ex) {
    
                    this._dialog.ShowException(ex.Message);
                }
            }
    
            public bool CanSaveItem() {
                return IsValid;
            }
    
          ..............
            #endregion
        }
    }
    Entity
    using System;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Waf.Foundation;
    
    namespace Domain {
        internal interface IItem {
            [Required(ErrorMessage = "Please enter Title")]
            [StringLength(100, ErrorMessage = "The maximum length is 100")]
            string Name { get; set; }
        }
    
        [MetadataType(typeof(IItem))]
        public partial class Item : IItem, IDataErrorInfo, IFormattable {
            [NonSerialized]
            private readonly DataErrorInfoSupport dataErrorInfoSupport;
    
    
            public Item() {
                ID = Guid.NewGuid();
                dataErrorInfoSupport = new DataErrorInfoSupport(this);
            }   
    
    
            string IDataErrorInfo.this[string memberName] { get { return dataErrorInfoSupport[memberName]; } }
    
            public string Error {
                get {
                    return dataErrorInfoSupport.Error;
                }
            }
        }
    }
    Έχω κάνει και αυτο το post, αλλα είπα να κάνω καινούριο για να είναι πιο ξεκάθαρο το πρόβλημα που αντιμετωπίζω.



    αν δεν το θες, www.antallakseto.gr
    Δημοσίευση στην κατηγορία: , , ,
Δείτε όλες τις δημοσιεύσεις της Θεματική Ενότητας
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems