I'm doing an app that uses the Microsoft.Maps and I'm having to problems that I hope that you can help me solving. (Taking into account that I'm using C# with MVVM architecture and XAML)
Q1: I'm defining the Center position as (0,0) and I'm trying to change it programatically but for some reason before the map is "Loaded" the center doesn't change. How can I do it?
Q2: I'm adding my pushpinn and some friends pushpins (their location are given) and I want to focus the map as somekind of boundedbox to focus only myself and my friends. How can I do this keeping the architecture?
XAML VIEW
<Grid>
<m:Map x:Name="MyMap" CredentialsProvider="mycredential" Center="{Binding MyCurrentPos}" ZoomLevel="16">
<m:MapItemsControl ItemsSource="{Binding PushpinList}">
<m:MapItemsControl.ItemTemplate>
<DataTemplate>
<m:Pushpin Location="{Binding location}" Background="Red"/>
</DataTemplate>
</m:MapItemsControl.ItemTemplate>
</m:MapItemsControl>
</m:Map>
</Grid>
C# VIEWMODEL
public OverViewViewModel() {
MyCurrentPos = "0,0";
getLocation();
}
private ObservableCollection<PushPinHelper> _pushpinList;
public ObservableCollection<PushPinHelper> PushpinList
{
get
{
if (_pushpinList == null)
{
_pushpinList = new ObservableCollection<PushPinHelper>();
}
return _pushpinList;
}
set { _pushpinList = value; }
}
public void getLocation()
{
GeoCoordinateWatcher watcher = new GeoCoordinateWatcher();
watcher.PositionChanged += Watcher_PositionChanged;
watcher.TryStart(false, TimeSpan.FromMilliseconds(1000)); // try start
}
private void Watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
GeoCoordinate geo = new GeoCoordinate(e.Position.Location.Latitude, e.Position.Location.Longitude);
PushPinHelper pp = new PushPinHelper(geo.ToString());
MyCurrentPos = geo.ToString();
OnPropertyChanged("MyCurrentPos");
PpHelper = pp;
OnPropertyChanged("PpHelper");
addMyself(pp);
}
public void addMyself(PushPinHelper geo)
{
PushpinList.Add(geo);
OnPropertyChanged("PushpinList");
}
private PushPinHelper _ppHelper;
public PushPinHelper PpHelper
{
get { return _ppHelper; }
set
{
_ppHelper = value;
}
}
// CLASS PushpinHelper
public class PushPinHelper
{
public PushPinHelper(string loc)
{
location = loc;
}
public string location { get; set; }
}
Related
So I'm making a slot machine in C#. I'm really new to C# and I am really bad at it.
Up to this point my project has been going fine. But now I want to randomize the images shown, when the 'spin' Button is clicked.
I've tried a lot of different things. The solutions I have found are either with the use of a PictureBox or nothing close to what I'm working on.
If someone could take a look at my code and push me in the right direction, I would be really grateful.
Thanks in advance!
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
namespace Prb.Slot.Machine.Wpf
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
int CoinInsert = 0;
private static Random random;
public enum SlotMachineIcon
{
Banana,
BigWin,
Cherry,
Lemon,
Orange,
Plum,
Seven,
Strawberry,
Watermelon
}
public MainWindow()
{
InitializeComponent();
}
private static void Init()
{
if (random == null) random = new Random();
}
public static int Random(int min, int max)
{
Init();
return random.Next(min, max);
}
void UpdateImage(Image wpfImage, SlotMachineIcon newIcon)
{
DirectoryInfo directoryInfo = new DirectoryInfo(Environment.CurrentDirectory);
directoryInfo = new DirectoryInfo(directoryInfo.Parent.Parent.Parent.Parent.FullName);
Uri uri = new Uri($"{directoryInfo.FullName}/images/{newIcon}.png");
wpfImage.Source = new BitmapImage(uri);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
lblCoinsInserted.Content = 0;
lblCoinBalance.Content = 0;
lblCoinsWon.Content = 0;
UpdateImage(imgLeft, SlotMachineIcon.Cherry);
UpdateImage(imgMiddle, SlotMachineIcon.Banana);
UpdateImage(imgRight, SlotMachineIcon.Seven);
}
private void btnInsertCoins_Click(object sender, RoutedEventArgs e)
{
int.TryParse(txtInsertCoins.Text, out int InsertCoins);
if (InsertCoins > 0)
{
CoinInsert += int.Parse(txtInsertCoins.Text.ToString());
lblCoinBalance.Content = (int)lblCoinBalance.Content + Convert.ToInt32(txtInsertCoins.Text);
lblCoinsInserted.Content = CoinInsert;
txtInsertCoins.Clear();
}
else
{
MessageBox.Show("Gelieve strikt positieve getallen in te vullen", "Ongeldig aantal munten", MessageBoxButton.OK, MessageBoxImage.Warning);
txtInsertCoins.Clear();
}
}
private void btnSpin_Click(object sender, RoutedEventArgs e)
{
int InsertedCoins = Convert.ToInt32(lblCoinsInserted.Content);
int CoinsBalance = Convert.ToInt32(lblCoinBalance.Content);
/*var v = Enum.GetValues(typeof(SlotMachineIcon));
int number = random.Next(10);*/
if (InsertedCoins == 0 | CoinsBalance == 0)
{
MessageBox.Show("Gelieve eerst munten in te werpen", "Geen munten ingeworpen", MessageBoxButton.OK, MessageBoxImage.Warning);
}
else
{
lblCoinBalance.Content = CoinsBalance - 1;
UpdateImage(imgLeft, SlotMachineIcon.Strawberry);
UpdateImage(imgMiddle, SlotMachineIcon.Watermelon);
UpdateImage(imgRight, SlotMachineIcon.Watermelon);
}
}
}
}
Edit: moved out random declaration as #EmondErno pointed it out.
This method returns a random icon every time you call it:
private Random random = new();
private SlotMachineIcon GetRandomIcon()
{
return (SlotMachineIcon)random.Next(10); //don't forget to update this number if you add or remove icons
}
Then call it in every UpdateImage method like:
UpdateImage(imgLeft, GetRandomIcon());
UpdateImage(imgMiddle, GetRandomIcon());
UpdateImage(imgRight, GetRandomIcon());
You're trying to do everything in the code behind, which is a terrible mistake for many reasons, among which your program will get hard to maintain read and update at some point and you are tight coupling the view and the logic of your program. You want to follow the MVVM pattern and put only in the code behind only the logic of the view (no data).
Also in your code, you're reinventing the updating system that already exists in WPF, you want to use the databinding and WPF updating system and get rid of all "update icon" logic in your program.
This is a ViewModel that you could use (.net 5.0):
public class SlotViewModel: ISlotViewModel, INotifyPropertyChanged
{
private Random _r = new();
private int _slotChoicesCount;
private SlotSet _currentSlotSet;
private ICommand _spinCommand;
public SlotViewModel()
{
_slotChoicesCount = Enum.GetNames(typeof(SlotMachineIcon)).Length;
}
private SlotSet GetNewSet() => new(Enumerable.Range(0,3).Select(o => (SlotMachineIcon)_r.Next(_slotChoicesCount)).ToList());
public SlotSet CurrentSlotSet
{
get => _currentSlotSet;
set
{
if (Equals(value, _currentSlotSet)) return;
_currentSlotSet = value;
OnPropertyChanged();
}
}
public ICommand SpinCommand => _spinCommand ??= new DelegateCommand(s => { CurrentSlotSet = GetNewSet(); }, s => true);
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
The most important part is that your ViewModel implements INotifyPropertyChanged. When you uses SpinCommand, it updates the property CurrentSlotSet, and that's all you need to worry about. All the rest is taken care of by the WPF databinding system.
SlotSet is a convenient way to present an immutable result:
public class SlotSet
{
public SlotMachineIcon Left { get; }
public SlotMachineIcon Middle { get; }
public SlotMachineIcon Right { get; }
public SlotSet(IList<SlotMachineIcon> triad)
{
Left = triad[0];
Middle = triad[1];
Right = triad[2];
}
public bool IsWinner => Left == Middle && Middle == Right; // just an example
}
ISlotViewModel is the interface (contract) that your ViewModel satisfies.
public interface ISlotViewModel
{
ICommand SpinCommand { get; }
SlotSet CurrentSlotSet { get; set; }
}
The helper class DelegateCommand:
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<object> execute, Predicate<object> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
In your View, XAML part, your only need something as simple as this:
<Button Command="{Binding SpinCommand}">spin</Button>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding CurrentSlotSet.Left}"/>
<Image Source="{Binding CurrentSlotSet.Middle}"/>
<Image Source="{Binding CurrentSlotSet.Right}"/>
</StackPanel>
And in the Windows markup has this:
xmlns:local="clr-namespace:SlotMachine"
d:DataContext="{d:DesignInstance Type=local:SlotViewModel, IsDesignTimeCreatable=True}"
The code behind is as simple as this:
public ISlotViewModel ViewModel
{
get { return (ISlotViewModel)DataContext; }
set { DataContext = value; }
}
public SlotView() // or MainWindow
{
InitializeComponent();
ViewModel = new SlotViewModel();
}
The only thing missing here is to add a converter in each of your <Image, which will convert a SlotMachineIcon value into the image path.
PS: if you don't have resharper, you may need this class too:
[AttributeUsage(AttributeTargets.Method)]
public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute
{
public NotifyPropertyChangedInvocatorAttribute() { }
public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName)
{
ParameterName = parameterName;
}
[CanBeNull] public string ParameterName { get; }
}
I have an object class that derives from BoxView. The object has TouchEffect attached and when the OnTouchAction starts, I change the object's properties.
I would also like to change the property of a label based on the text attached to the string that label is bound to.
What I did is I created an instance of the page that contains bindable string and label, then, I tried to change the value of string by referencing it in code inside the OnTouchAction method.
I don't get errors and the Breakpoint tells me that code arrives to the line, but the label is not being updated.
I am trying to update the string from the class that is not the same where the string is.
Is there anyone who could help me out here?
class Element : BoxView
{
List<long> ids = new List<long>();
MainPage mainPage = new MainPage();
public event EventHandler StatusChanged;
public Element()
{
TouchEffect effect = new TouchEffect();
effect.TouchAction += OnTouchEffectAction;
Effects.Add(effect);
}
public Color DefaultColor { set; get; }
public Color HighlightColor { set; get; }
public bool IsPressed { private set; get; }
void OnTouchEffectAction(object sender, TouchActionEventArgs args)
{
switch (args.Type)
{
case TouchActionType.Pressed:
AddToList(args.Id);
mainPage.LeftLabelText = "entered";
break;
case TouchActionType.Entered:
if (args.IsInContact)
{
AddToList(args.Id);
mainPage.LeftLabelText = "entered";
}
break;
case TouchActionType.Moved:
break;
case TouchActionType.Released:
case TouchActionType.Exited:
RemoveFromList(args.Id);
break;
}
}
void AddToList(long id)
{
if (!ids.Contains(id))
{
ids.Add(id);
}
CheckList();
}
void RemoveFromList(long id)
{
if (ids.Contains(id))
{
ids.Remove(id);
}
CheckList();
}
void CheckList()
{
if (IsPressed != ids.Count > 0)
{
IsPressed = ids.Count > 0;
Color = IsPressed ? HighlightColor : DefaultColor;
mainPage.LeftLabelText = "entered";
StatusChanged?.Invoke(this, EventArgs.Empty);
}
}
}
and the MainPage relevant code:
Element element = new Element();
element.HighlightColor = Color.Accent;
element.DefaultColor = Color.Transparent;
element.Color = bar.DefaultColor;
element.HeightRequest = sGrid.Height;
element.VerticalOptions = LayoutOptions.End;
(...) // adding element view to the grid.
The string:
public string _leftLabelText = "testing";
public string LeftLabelText
{
get => _leftLabelText;
set
{
_leftLabelText = value;
NotifyPropertyChanged("LeftLabelText");
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged2;
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged2?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
<Label x:Name="leftLabel" x:FieldModifier="public" Text="{Binding LeftLabelText, Mode=TwoWay}" TextColor="Black" FontSize="10" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"/>
Is it possible to have one ViewModel for multiple dynamic Tabs? Meaning that, whenever I create a new tab, it should use the same instance of ViewModel so I can retrieve information and also prevent each Tab from sharing data/showing the same data.
The setting I'm thinking of using it in would be for a payroll application where each employee's payslip can be updated from each tab. So the information should be different in each Tab.
Is this possible?
Update: Added code
MainViewModel where Tabs Collection is handled:
public ObservableCollection<WorkspaceViewModel> Workspaces { get; set; }
public MainViewModel()
{
Workspaces = new ObservableCollection<WorkspaceViewModel>();
Workspaces.CollectionChanged += Workspaces_CollectionChanged;
}
void Workspaces_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null && e.NewItems.Count != 0)
foreach (WorkspaceViewModel workspace in e.NewItems)
workspace.RequestClose += this.OnWorkspaceRequestClose;
if (e.OldItems != null && e.OldItems.Count != 0)
foreach (WorkspaceViewModel workspace in e.OldItems)
workspace.RequestClose -= this.OnWorkspaceRequestClose;
}
private void OnWorkspaceRequestClose(object sender, EventArgs e)
{
CloseWorkspace();
}
private DelegateCommand _exitCommand;
public ICommand ExitCommand
{
get { return _exitCommand ?? (_exitCommand = new DelegateCommand(() => Application.Current.Shutdown())); }
}
private DelegateCommand _newWorkspaceCommand;
public ICommand NewWorkspaceCommand
{
get { return _newWorkspaceCommand ?? (_newWorkspaceCommand = new DelegateCommand(NewWorkspace)); }
}
private void NewWorkspace()
{
var workspace = new WorkspaceViewModel();
Workspaces.Add(workspace);
SelectedIndex = Workspaces.IndexOf(workspace);
}
private DelegateCommand _closeWorkspaceCommand;
public ICommand CloseWorkspaceCommand
{
get { return _closeWorkspaceCommand ?? (_closeWorkspaceCommand = new DelegateCommand(CloseWorkspace, () => Workspaces.Count > 0)); }
}
private void CloseWorkspace()
{
Workspaces.RemoveAt(SelectedIndex);
SelectedIndex = 0;
}
private int _selectedIndex = 0;
public int SelectedIndex
{
get { return _selectedIndex; }
set
{
_selectedIndex = value;
OnPropertyChanged("SelectedIndex");
}
}
WorkspaceViewModel:
public PayslipModel Payslip { get; set; }
public WorkspaceViewModel()
{
Payslip = new PayslipModel();
SaveToDatabase = new DelegateCommand(Save, () => CanSave);
SelectAll = new DelegateCommand(Select, () => CanSelect);
UnSelectAll = new DelegateCommand(UnSelect, () => CanUnSelect);
}
public ICommand SaveToDatabase
{
get; set;
}
private bool CanSave
{
get { return true; }
}
private async void Save()
{
try
{
MessageBox.Show(Payslip.Amount.ToString());
}
catch (DbEntityValidationException ex)
{
foreach (var en in ex.EntityValidationErrors)
{
var exceptionDialog = new MessageDialog
{
Message = { Text = string.Format("{0}, {1}", en.Entry.Entity.GetType().Name, en.Entry.State) }
};
await DialogHost.Show(exceptionDialog, "RootDialog");
foreach (var ve in en.ValidationErrors)
{
exceptionDialog = new MessageDialog
{
Message = { Text = string.Format("{0}, {1}", ve.PropertyName, ve.ErrorMessage) }
};
await DialogHost.Show(exceptionDialog, "RootDialog");
}
}
}
catch (Exception ex)
{
var exceptionDialog = new MessageDialog
{
Message = { Text = string.Format("{0}", ex) }
};
await DialogHost.Show(exceptionDialog, "RootDialog");
}
}
public event EventHandler RequestClose;
private void OnRequestClose()
{
if (RequestClose != null)
RequestClose(this, EventArgs.Empty);
}
private string _header;
public string Header
{
get { return _header; }
set
{
_header = value;
OnPropertyChanged("Header");
}
}
Payroll UserControl where WorkspaceViewModel is DataContext:
public Payroll()
{
InitializeComponent();
DataContext = new WorkspaceViewModel();
}
Payroll.xaml Tabcontrol:
<dragablz:TabablzControl ItemsSource="{Binding Workspaces}" SelectedIndex="{Binding SelectedIndex}" BorderBrush="{x:Null}">
<dragablz:TabablzControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</dragablz:TabablzControl.ItemTemplate>
<dragablz:TabablzControl.ContentTemplate>
<DataTemplate>
<ContentControl Margin="16">
<local:TabLayout DataContext="{Binding Path=Payslip, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="tabLayout"/>
</ContentControl>
</DataTemplate>
</dragablz:TabablzControl.ContentTemplate>
</dragablz:TabablzControl>
This works as expected, each tab displays different info and bindings work okay. However, I'm unable to retrieve the info in the MessageBox.
I'm not sure if I totally understand your question but if you need a Window with a tabcontrol, in which each tab refers to an employee, then you will have to bind the ItemsSource of the tabcontrol to a list of the ViewModel.
It is not possible to bind all tabpages to the same instance because then the tabpages will all do the same, and show the same information.
I couldn't get it to work the way I had it, so I placed the save button inside the view that has DataContext set to where employee's info are loaded and got it to work from there, since it directly accesses the properties.
ViewModels should have a 1:1 relationship with the model. In your TabControl's DataContext, let's say you have properties like:
public ObservableCollection<EmployeeViewModel> Employees {get;set;}
public EmployeeViewModel CurrentEmployee
{
get { return _currentEmployee;}
set
{
_currentEmployee = value;
OnPropertyChanged("CurrentEmployee");
}
}
where Employees is bound to ItemsSource of the TabControl, and CurrentEmployee to CurrentItem. To create a new tab:
var employee = new Employee();
var vm = new EmployeeViewModel(employee);
Employees.Add(vm);
CurrentEmployee = vm;
If you want a save button outside of the TabControl, just set its DataContext to CurrentEmployee.
I hope this helps!
Edit:
Two things I think are causing problems:
Payroll.xaml should be bound to MainViewModel since that's where the Workspaces collection is.
Do not instantiate ViewModels in your view's code behind. Use a DataTemplate instead (see this question).
Take a look at Josh Smith's MVVM demo app (source code)
I have the following TreeView:
<TreeView x:Name="Folders" Grid.Column="0" SelectedItemChanged="Folders_SelectedItemChanged" ItemsSource="{Binding Items}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type Local:OpenFolderItem}" ItemsSource="{Binding Children}" >
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" Margin="0,2,0,2">
<Image Source="{Binding Path=Image, Mode=OneTime}" Stretch="Fill" />
<TextBlock Text="{Binding Name}" Margin="5,0" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
In the code-behind, I would like to change the root directory so that it auto-expands to that directory.
For example:
The following image shows what happens when I open a dialog:
Say I wish to start with the directory: "E:\Sequences", when I start the dialog, I would like it to look like this:
Here's the VM:
Update 1
public class OpenFolderItem : ViewModelBase
{
#region Private Members
private string m_path;
ICollection<OpenFolderItem> m_children;
bool m_isSelected;
#endregion Private Members
#region Constructors
public OpenFolderItem() { }
public OpenFolderItem(string path) { Path = path; }
#endregion
#region Properties
public bool IsExpanded { get; set; }
public string Name { get; set; }
public string Path
{
get
{
return m_path;
}
set
{
m_path = value;
}
}
public ImageSource Image { get; set; }
public virtual ICollection<OpenFolderItem> Children
{
get { return m_children ?? (m_children = LoadChildren()); }
set { m_children = value; }
}
#endregion Properties
#region Private Functions
private ICollection<OpenFolderItem> LoadChildren()
{
var items = new List<OpenFolderItem>();
try
{
items.AddRange(Directory.GetDirectories(Path).Select(directory => new OpenFolderItem(directory)
{
Name = System.IO.Path.GetFileName(directory),
Image = FileInfoHelper.GetFolderImage(false),
IsExpanded = true
}));
items = items.OrderBy(o => o.Path , new Comparer.NaturalStringComparer()).ToList();
}
catch (UnauthorizedAccessException) { }
catch (ArgumentException) { }
catch (DirectoryNotFoundException) { }
return new ReadOnlyCollection<OpenFolderItem>(items);
}
#endregion Private Functions
}
And here's the Xaml.cs:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
namespace OpenDialogs
{
/// <summary>
/// Interaction logic for OpenDialogView.xaml
/// </summary>
public partial class OpenDialogView
{
#region Private Members
private Window m_window;
#endregion Private Members
#region Constructor
/// <summary>
/// The OpenDialogView's constructor.
/// </summary>
public OpenDialogView()
{
InitializeComponent();
}
#endregion Constructor
#region Properties
public string IconFile { get; set; }
#endregion Properties
#region Private Functions
private void Folders_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
ViewModel.SelectedFolder = e.NewValue as OpenFolderItem;
}
private void OnShow(object sender, OpenDialogEventArgs e)
{
try
{
//var b = new OpenFolderItem();
//b.Name = "Sequences";
//b.Path = #"E:\Sequences";
//ViewModel.SelectedFolder = b;
//ItemCollection ic = Folders.Items;
//string yourNode = "Sequences";
//foreach (TreeViewItem tvi in ic)
//{
// if (yourNode.StartsWith(tvi.Tag.ToString()))
// {
// tvi.IsExpanded = true;
// break;
// }
//}
m_window = new Window
{
Content = this,
SizeToContent = SizeToContent.Manual,
ResizeMode = ResizeMode.CanResizeWithGrip,
WindowStyle = WindowStyle.SingleBorderWindow,
Title = e.Caption,
ShowInTaskbar = false,
Topmost = true,
Height = 600,
Width = 1000,
Owner = e.Owner,
WindowStartupLocation = e.StartupLocation,
};
if (!String.IsNullOrEmpty(IconFile))
m_window.Icon = BitmapFrame.Create(new Uri("pack://application:,,,/" + IconFile, UriKind.RelativeOrAbsolute));
m_window.ShowDialog();
}
catch (Exception)
{
Console.WriteLine();
}
}
private void OnClose(object sender, OpenDialogEventArgs e)
{
m_window.Close();
}
#endregion Private Functions
}
}
I'm pretty sure I'm being blocked by the 'HierarchicalDataTemplate'. Is that correct? Any way of making it work?
You'd have to loop through the nodes and set to necessary nodes IsExpanded properties to true.
Try this code in mainWindow.xaml.cs:
public MainWindow()
{
InitializeComponent();
ExtendTree();
}
private void ExtendTree()
{
ItemCollection ic = treeView.Items;
string yourNode = "Sequences";
foreach (var tvi in ic)
{
if (yourNode.StartsWith((TreeViewItem)tvi.Tag.ToString()))
{
(TreeViewItem)tvi.IsExpanded = true;
break;
}
}
}
I got some problem in showing download percentage in GridView of WCF. I used MVVM pattern.
Here is my background worker in application start:
public partial class MainWindow : Window
{
public MainWindow()
{
Overall.EverythingOk = "Nothing";
InitializeComponent();
//IRepo repo = new Repo();
ViewModel.MainWindowsViewModel viewModel = new ViewModel.MainWindowsViewModel();
this.DataContext = viewModel;
BackGroundThread bgT = new BackGroundThread();
bgT.bgWrk.RunWorkerAsync();
}}
Here is the DoWork function in BackGroundTHread class
public void bw_DoWork(object sender, DoWorkEventArgs e)
{
if (!Overall.stopStatus)
{
for (int i=0; i < 10000; i++)
{
Overall.PercentageDwnd = i;
Overall.caseRefId = "999999";
if (i == 9998)
{
i = 1;
}
}
}
}
Overall.PercentageDwnd and Overall.caseRefId are static variable (you can call from everywhere in the application) and always update until the background worker completed. I got another ViewModel called TestViewModel and here it is.
public class TestViewModel:BindableBase
{
private String _UpdatePer=Overall.PercentageDwnd.ToString();
public String UpdatePercentage
{
get { return _UpdatePer; }
set { SetProperty(ref _UpdatePer, value); }
}
private ObservableCollection _ViewAKA = new ObservableCollection();
private tblTransaction model;
public TestViewModel(tblTransaction model)
{
// TODO: Complete member initialization
}
public ObservableCollection ViewAKA
{
get { return _ViewAKA; }
set { SetProperty(ref _ViewAKA, value); }
}
}
I bind with TestView.xaml file
<Window x:Class="EmployeeManager.View.TestView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestView" Height="359.774" Width="542.481">
<Grid Margin="0,0,2,0">
<Label Content="{Binding UpdatePercentage,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Background="Red" Foreground="White" Margin="130,86,0,0" VerticalAlignment="Top" Width="132" Height="39">
</Label>
</Grid>
</Window>
There is no real time update at Label even though I bind UpdatePercentage to it. How can I update real time to label?
The problem is that you are updating the static properties, which are not bound to anything. You need to update and raise the property changed notification for the properties which are bound to the label controls, i.e. UpdatePercentage
Can you pass the TestViewModel instance into the RunWorkerAsync call?
bgT.bgWrk.RunWorkerAsync(testViewModel);
And then access in the DoWork event handler:
public void bw_DoWork(object sender, DoWorkEventArgs e)
{
if (!Overall.stopStatus)
{
var viewModel = e.Argument as TestViewModel;
for (int i=0; i < 10000; i++)
{
Overall.PercentageDwnd = i;
viewModel.UpdatePercentage = i;
Overall.caseRefId = "999999";
if (i == 9998)
{
i = 1;
}
}
}
}
Here is answer link:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/02a7b9d1-1c26-4aee-a137-5455fee175b9/wpf-percentage-status-shown-in-label-mvvm?forum=wpf
i need to trigger when the Overall.PercentageDwnd property changes.
Edited
In Overall Class:
public class Overall
{
private static int _percentage;
public static int PercentageDwnd
{
get { return _percentage; }
set
{
_percentage = value;
//raise event:
if (PercentageDwndChanged != null)
PercentageDwndChanged(null, EventArgs.Empty);
}
}
public static string caseRefId { get; set; }
public static bool stopStatus { get; set; }
public static event EventHandler PercentageDwndChanged;
}
In TestViewModel:
public class TestViewModel : BindableBase
{
private String _UpdatePer = Overall.PercentageDwnd.ToString();
public String UpdatePercentage
{
get { return _UpdatePer; }
set { SetProperty(ref _UpdatePer, value); }
}
public TestViewModel(tblTransaction model)
{
Overall.PercentageDwndChanged += Overall_PercentageDwndChanged;
// TODO: Complete member initialization
}
private void Overall_PercentageDwndChanged(object sender, EventArgs e)
{
this.UpdatePercentage = Overall.PercentageDwnd.ToString();
}
}
Since you have bound the TextBlock in the view to the UpdatePercentage source property, you need to set this one and raise the PropertyChanged event whenever you want to update the Label in the view. This means that you need to know when the Overall.PercentageDwnd property changes.
Credit to
Magnus (MM8)
(MCC, Partner, MVP)
Thanks All