What controls are used for making terminal using C# and WPF - c#

I'm developing a Terminal Software that send command and data, receive log and data, etc...
Terminal S/W communicate with Arm Cortex via USB Interface.
For developing, I used C# and WPF textbox for terminal screen.
But, I faced some problem.
Updating textbox is very slow compared to USB interfaced.
How can I solve this problem?
If you have solutions or know usercontrol made by WPF for terminal.
Please let me know.
Thank you.
Additional Infomation.
1.string property for binding to TextBox
public string TestString
{
get { return _testString; }
set
{
_testString = value;
RaisePropertyChangedEvent("TestString");
}
}
2.test functions for updating log
StringBuilder testBulider = new StringBuilder();
testBulider.Capacity = 1000000;
for (int i = 0; i < 1000; ++i)
{
testBulider.Append(i.ToString("x4") + "\n");
testString = testBulider.ToString(); // Very Slow Point
}
3.Capture of performance analyzer result in VS2012

StringBuilder may not be the way to go here, and is typically used when you are appending a lot of data in a loop or other process, and wish to call ToString at the very end. The performance is better in that case than say, doing a bunch of explicit string concatenations because of the memory allocation overhead.
I'm not entirely certain on your application but I'd guess you just want to display some output from the terminal. I'd suggest you store the lines of text in an ObservableCollection property and add to it as you receive new lines. I do something similar and have an extended RichTextBox with a DataSource property that I use to display the lines. I'm sure there are faster ways to do this (RichTextBox is NOT known for its performance, and I'm constructing a new inline block every time a line is added), but I've never noticed any performance issues - and it allowed me to get creative with color coding formatted based on event type etc.
Anyway, I've tried my best to copy what I have while stripping out my specific implementation details, I didn't test this specifically.
EventLogBox class:
public class EventLogBox : RichTextBox
{
public EventLogBox()
{
}
static EventLogBox()
{
RichTextBox.IsReadOnlyProperty.OverrideMetadata(
typeof(EventLogBox),
new FrameworkPropertyMetadata(true));
RichTextBox.VerticalScrollBarVisibilityProperty.OverrideMetadata(
typeof(EventLogBox),
new FrameworkPropertyMetadata(ScrollBarVisibility.Visible));
RichTextBox.FontFamilyProperty.OverrideMetadata(
typeof(EventLogBox),
new FrameworkPropertyMetadata(new FontFamily("Courier New")));
}
private void AddItem(string pEntry)
{
Paragraph a = new Paragraph();
Run messageRun = new Run(pEntry);
a.Inlines.Add(messageRun);
this.Document.Blocks.Add(a);
this.ScrollToEnd();
}
private void LoadNewItems()
{
this.Document.Blocks.Clear();
foreach (string entry in DataSource)
{
this.AddItem(entry);
}
}
/// <summary>
/// The source of content (EventLogEntrys)
/// </summary>
public IEnumerable<string> DataSource
{
get
{
return (IEnumerable<string>)GetValue(DataSourceProperty);
}
set
{
SetValue(DataSourceProperty, value);
}
}
/// <summary>
/// Using a DependencyProperty as the backing store for <see cref="DataSource"/>.
/// This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty DataSourceProperty =
DependencyProperty.Register
(
"DataSource",
typeof(IEnumerable<string>), typeof(EventLogBox),
new PropertyMetadata
(
new ObservableQueue<string>(),
new PropertyChangedCallback(DataSourcePropertyChanged)
),
new ValidateValueCallback(IsValidDataSourceProperty)
);
/// <summary>
/// We also ned to impliment the INotifyCollectionChanged interface
/// in order for everything to work properly.
/// </summary>
/// <param name="pValue"></param>
/// <returns></returns>
private static bool IsValidDataSourceProperty(object pValue)
{
return pValue is INotifyCollectionChanged;
}
/// <summary>
/// Callback when the DataSourceProperty changes. Setup the new
/// CollectionChanged events, etc.
/// </summary>
/// <param name="pSender"></param>
/// <param name="pArgs"></param>
private static void DataSourcePropertyChanged(DependencyObject pSender,
DependencyPropertyChangedEventArgs pArgs)
{
EventLogBox s = ((EventLogBox)pSender);
((INotifyCollectionChanged)s.DataSource).CollectionChanged -=
new NotifyCollectionChangedEventHandler(
s.DataSource_CollectionChanged);
((INotifyCollectionChanged)s.DataSource).CollectionChanged +=
new NotifyCollectionChangedEventHandler(
s.DataSource_CollectionChanged);
s.LoadNewItems();
}
/// <summary>
///
/// </summary>
/// <param name="pSender"></param>
/// <param name="pArgs"></param>
private void DataSource_CollectionChanged(object pSender,
NotifyCollectionChangedEventArgs pArgs)
{
IList n = pArgs.NewItems;
switch (pArgs.Action)
{
case NotifyCollectionChangedAction.Add:
{
foreach (string cle in pArgs.NewItems)
{
AddItem(cle);
}
break;
}
case NotifyCollectionChangedAction.Remove:
{
for (int i = pArgs.OldStartingIndex;
i < pArgs.OldItems.Count; i++)
{
this.Document.Blocks.Remove(this.Document.Blocks.ElementAt(i));
}
break;
}
case NotifyCollectionChangedAction.Replace:
{
break;
}
}
}
}
Property In ViewModel
private ObservableCollection<string> mLines = new ObservableCollection<string>();
public ObservableCollection<string> Lines
{
get
{
return mLines;
}
}
In XAML:
<local:EventLogBox DataSource="{Binding Path=Lines}" Height="100"/>
Then when you receive a new line from your terminal, call
Lines.Add(newLine);

Related

Accelerometer.Shaken event on UWP not working, any solutions?

I was trying to implement some sort of handler to the Accelerometer.Shaken event and then I discovered that this event isn't supported yet on Windows 10, as can be seen from the answer here.
Now, even though the shaken event doesn't work, the Accelerometer.ReadingChanged event works just fine.
So I was thinking, would it be possible to manually detect a shake gesture from that data? I mean, it's probably possible, but I really wouldn't know where to start, does anyone have an idea?
You get the X, Y and Z coordinates every x milliseconds, there must be some way to calculate a shake gesture from that data.
Thanks for your help!
Never mind, I ended up writing my own class to solve the problem, I'll leave it here in case it gets useful for someone else:
/// <summary>
/// A static class that manages the Shaken event for the Accelerometer class
/// </summary>
public static class CustomAccelerometer
{
// The minimum acceleration value to trigger the Shaken event
private const double AccelerationThreshold = 2;
// The minimum interval in milliseconds between two consecutive calls for the Shaken event
private const int ShakenInterval = 500;
private static bool _AccelerometerLoaded;
private static Accelerometer _DefaultAccelerometer;
/// <summary>
/// Gets the current Accelerometer in use
/// </summary>
private static Accelerometer DefaultAccelerometer
{
get
{
if (!_AccelerometerLoaded)
{
_AccelerometerLoaded = true;
_DefaultAccelerometer = Accelerometer.GetDefault();
}
return _DefaultAccelerometer;
}
}
private static DateTime _ShakenTimespan = DateTime.Now;
private static bool _Enabled;
/// <summary>
/// Gets or sets whether or not the Accelerometer is currently enabled and can raise the Shaken event
/// </summary>
public static bool Enabled
{
get { return _Enabled; }
set
{
if (_Enabled != value && DefaultAccelerometer != null)
{
if (value) DefaultAccelerometer.ReadingChanged += _DefaultAccelerometer_ReadingChanged;
else DefaultAccelerometer.ReadingChanged -= _DefaultAccelerometer_ReadingChanged;
}
_Enabled = value;
}
}
// Handles the ReadingChanged event and raises the Shaken event when necessary
private static void _DefaultAccelerometer_ReadingChanged(Accelerometer sender, AccelerometerReadingChangedEventArgs args)
{
double g = Math.Round(args.Reading.AccelerationX.Square() + args.Reading.AccelerationY.Square() + args.Reading.AccelerationZ.Square());
if (g > AccelerationThreshold && DateTime.Now.Subtract(_ShakenTimespan).Milliseconds > ShakenInterval)
{
_ShakenTimespan = DateTime.Now;
Shaken?.Invoke(null, EventArgs.Empty);
}
}
/// <summary>
/// Raised whenever the Accelerometer detects a shaking gesture
/// </summary>
public static event EventHandler Shaken;
}
To use it, just enable it and subscribe to its event:
CustomAccelerometer.Enabled = true;
CustomAccelerometer.Shaken += (s, e) =>
{
Debug.WriteLine("The device was shaken!");
};
EDIT: forgot to add the Square method code, here it is:
/// <summary>
/// Returns the square of the given double value
/// </summary>
/// <param name="value">The input value</param>
public static double Square(this double value) => value * value;

Single-Variable Binding in Win Forms: What am I doing wrong?

I've been trying to make binding work for two labels in a WinForm, but I can't seem to figure out what I'm doing wrong. Currently, I'm implementing the INotifyPropertyChanged interface, and rigged it to a couple of properties within a Form. The current classes this affects are SessionForm.cs, the actual form, and Session.cs, the place where I keep all the information of the program. The labels in question, which are not mentioned in either class, are L_No, which holds the numerical reference of the Note in the musical Scale, and L_Note, which holds the visceral Note value (e.g. C, C#, etc.).
Allow me to explain what everything does within the classes. The program is designed to test your scale knowledge by asking you, based on the your chosen scale, what nth note of the scale is. You use the buttons on the form to make your choice.
These choices are recorded within the Session class, which has been edited to make this more succinct. The array of integers holds the indices of the notes in relation to the scale array, which is in the Scale object. For example, a typical Note array may hold these values: {1,3,0,2,6,1,3,...}. By using the array in the Scale object as a reference, these would translate into musical notes (e.g. D, F, C, E, B, D, F,...). The player's choices are stored within an array of NoteData objects.
In SessionForm.cs I'm manipulating that information over time. Each time a choice is or isn't made (depending on whether or not they attempted to guess in time), the value of the two Labels are changed: L_No, and L_Note. These two Labels are manipulated by the variables NoteIndex and LastNote, respectively. When these change in value, NotifyPropertyChanged occurs, and then the Labels should be updated...but they're not doing so.
Now, in the design section of the form, in the Properties window, I set up the Text property of each Label to be bound to their respective variables within the form, and set to update upon Property Change, but nothing seems to be working.
So what am I doing wrong?
Session.cs:
public class Session
{
public struct NoteData
{
public int Note;
public bool Correct;
public int GuessTime;
}
public Scale Scale;
/// <summary>
/// Holds the notes for one game
/// </summary>
public int[] Notes { get; private set; }
public NoteData[] Data { get; private set; }
/// <summary>
/// Creates a Session
/// </summary>
/// <param name="difficulty">The difficult of the session, refer to the Resources Class for determination.</param>
/// <param name="scale_used">The scale to be used. Refer to the Resources Class for determination.</param>
/// <param name="notes">The notes being used within this Session</param>
public Session(Resources.Difficulties difficulty, Scale scale_used, int[] notes)
{
ID = DateTime.Now;
Diff = difficulty;
Scale = scale_used;
Notes = notes;
Data = new NoteData[notes.Length];
internalIndex = 0;
}
/// <summary>
/// Stores Note input for each guessed
/// </summary>
/// <param name="index">The index of the note the player is currently on</param>
/// <param name="correct">Was the guess correct?</param>
/// <param name="remaining_time">How long did it take for them to guess?</param>
public void StoreNoteInput(int index, bool correct, int remaining_time)
{
if (internalIndex < Data.Length)
Data[internalIndex++] = new NoteData(index, remaining_time, correct);
}
}
SessionForm.cs:
public partial class SessionForm : Form, INotifyPropertyChanged
{
public Session curSession { get; private set; }
Resources.Notes last_note;
/// <summary>
/// The note index number in relation to the scale
/// </summary>
public int NoteIndex
{
get
{ return note_index; }
private set
{
if (note_index != value)
{
note_index = value;
NotifyPropertyChanged("NoteIndex");
}
}
}
/// <summary>
/// Represents the previous note being tested
/// </summary>
public Resources.Notes LastNote
{
get
{
return last_note;
}
private set
{
if (last_note != value)
{
last_note = value;
NotifyPropertyChanged("LastNote");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void TickDownTimer_Tick(object sender, EventArgs e)
{
remainingTime -= countingDown ? 1000 : 100;
if (remainingTime == 0)
{
if (countingDown)
{
countingDown = false;
TickDownTimer.Interval = 100;
}
if (curIndex > 0)
{
//you ran out of time on the last note
RecordNoteInput(curIndex - 1, false);
}
NextNote();
}
SetTimerText();
}
private void RecordNoteInput(int index, bool correct)
{
curSession.StoreNoteInput(index, correct, remainingTime);
NoteIndex = curSession.Notes[curIndex - 1];
LastNote = curSession.Scale.Notes[NoteIndex];
L_Note.ForeColor = correct ? Color.Green : Color.Red;
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
UPDATE: Here's the binding code that comes from SessionForm.Designer.cs:
this.sessionFormBindingSource1 = new System.Windows.Forms.BindingSource(this.components);
this.sessionFormBindingSource2 = new System.Windows.Forms.BindingSource(this.components);
this.sessionFormBindingSource = new System.Windows.Forms.BindingSource(this.components);
//
// L_Note
//
this.L_Note.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.sessionFormBindingSource1, "LastNote", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged, "C"));
this.L_Note.Text = " ";
//
// L_No
//
this.L_No.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.sessionFormBindingSource2, "NoteIndex", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged, "1", "N0"));
this.L_No.Text = " ";
The problem is the way you call NotifyPropertyChanged:
NotifyPropertyChanged("note_index");
and
NotifyPropertyChanged("last_note");
Just remove the strings from the calls like this
NotifyPropertyChanged();
and everything should be fine.
Edit: If it's not, then your bindings are not initialized correctly. Prove:
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
namespace Tests
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new TestForm());
}
}
class TestForm : Form, INotifyPropertyChanged
{
public TestForm()
{
var label = new Label { Parent = this, Left = 16, Top = 16, AutoSize = false, BorderStyle = BorderStyle.FixedSingle };
label.DataBindings.Add("Text", this, "NoteIndex");
var timer = new Timer { Interval = 200, Enabled = true };
timer.Tick += (sender, e) => NoteIndex = (NoteIndex + 1) % 10;
}
int note_index;
public int NoteIndex
{
get { return note_index; }
private set
{
if (note_index != value)
{
note_index = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

IList as dependency property, setter does not seem to be working

I have the following custom user control that derives from ComboBox:
public class EnumSourceComboBox : ComboBox
{
public static readonly DependencyProperty ExcludedItemsProperty =
DependencyProperty.Register(
"ExcludedItems",
typeof(IList),
typeof(EnumSourceComboBox),
new PropertyMetadata(
new List<object>()));
public EnumSourceComboBox()
{
this.ExcludedItems = new List<object>();
}
public IList ExcludedItems
{
get
{
return (IList)this.GetValue(EnumSourceComboBox.ExcludedItemsProperty);
}
set
{
this.SetValue(EnumSourceComboBox.ExcludedItemsProperty, value);
}
}
}
and I use it in XAML as follows:
<controls:EnumSourceComboBox>
<controls:EnumSourceComboBox.ExcludedItems>
<employeeMasterData:TaxAtSourceCategory>FixedAmount</employeeMasterData:TaxAtSourceCategory>
<employeeMasterData:TaxAtSourceCategory>FixedPercentage</employeeMasterData:TaxAtSourceCategory>
</controls:EnumSourceComboBox.ExcludedItems>
</controls:EnumSourceComboBox>
This builds fine and there's no XAML parse exception or something similar. However, the ExcludedItems always have count == 0, so the two items defined in XAML are not added to the list.
How do you define a dependency property to support this behavior?
Update: Here's the TaxAtSourceCategory enumeration:
public enum TaxAtSourceCategory
{
/// <summary>
/// The none.
/// </summary>
None,
/// <summary>
/// The fixed amount.
/// </summary>
FixedAmount,
/// <summary>
/// The fixed percentage.
/// </summary>
FixedPercentage,
// Has some more values, but I don't think that matters
}
In the following code there is the EnumSourceCombobox with the tracking of the changes in the collection.
There are both tracking of :
-the collection change (collection replaced with another on)
-and changes in the collection ( add/remove/clear)
public class EnumSourceComboBox : ComboBox
{
private ObservableCollection<TaxAtSourceCategory> previousCollection;
public static readonly DependencyProperty ExcludedItemsProperty =
DependencyProperty.Register(
"ExcludedItems",
typeof(ObservableCollection<TaxAtSourceCategory>),
typeof(EnumSourceComboBox),
new PropertyMetadata(null));
public ObservableCollection<TaxAtSourceCategory> ExcludedItems
{
get
{
return (ObservableCollection<TaxAtSourceCategory>)this.GetValue(EnumSourceComboBox.ExcludedItemsProperty);
}
set
{
this.SetValue(EnumSourceComboBox.ExcludedItemsProperty, value);
}
}
public EnumSourceComboBox()
{
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(EnumSourceComboBox.ExcludedItemsProperty, typeof(EnumSourceComboBox));
dpd.AddValueChanged(this, (o, e) =>
{
if (previousCollection != null)
previousCollection.CollectionChanged -= ExcludedItemsChanged;
previousCollection = ExcludedItems;
if (previousCollection != null)
previousCollection.CollectionChanged += ExcludedItemsChanged;
});
this.ExcludedItems = new ObservableCollection<TaxAtSourceCategory>();
}
void ExcludedItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// Take into account change in the excluded items more seriously !
MessageBox.Show("CollectionChanged to count " + ExcludedItems.Count);
}
}
Here is a link to the solution :
http://1drv.ms/1P8cMVc
Best use
#cguedel,
I tried your DependencyProperty code, and it runs fine.
I added two strings in the XAML content of the property instead of TaxAtSourceCategory instances
In the Loaded event of the window I had a count for the list of 2.
So may be you ve got Something to do with the TaxAtSourceCategory class.
And may be you could show the TaxAtSourceCategory code, check the constructor call...
Regards

How to change the language of the text on all control in the form

Is there a way to change the language of all the controls in the form in runtime?
For example, I have a button in the form and it has a text of "Hello". How can I change that into different language on runtime? dynamically every language that I can set. Is there a way to do it??
I've found an answer, but it seems that its not working it has something to do with cultureinfo. Any suggestions how to do it?
This is my code
public partial class Form1 : BaseLanguageForm
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.TriggerLanguageChange("fr-FR");
}
}
public class LanguageArgs : EventArgs
{
string _languageSymbol;
/// <summary>
/// Gets the language symble.
/// </summary>
public string LanguageSymbol
{
get { return _languageSymbol; }
}
/// <summary>
/// Initializes a new instance of the <see cref="LanguageArgs"/> class.
/// </summary>
/// <param name="symbol">The symbol.</param>
public LanguageArgs(string symbol)
{
this._languageSymbol = symbol;
}
}
public class BaseLanguageForm : Form
{
/// <summary>
/// Triggers the language change event.
/// </summary>
/// <param name="languageSymbol">The language symbol.</param>
protected void TriggerLanguageChange(string languageSymbol)
{
if (Form1.onLanguageChanged != null)
{
LanguageArgs args = new LanguageArgs(languageSymbol);
Form1.onLanguageChanged(this, args);
}
}
/// <summary>
/// This should be triggered whenever the combo box value chages
/// It is protected, just incase you want to do any thing else specific to form instacne type
/// </summary>
protected static event EventHandler<LanguageArgs> onLanguageChanged;
/// <summary>
/// This will be called from your form's constuctor
/// (you don't need to do anything, the base class constuctor is called automatically)
/// </summary>
public BaseLanguageForm()
{
//registering to the event
BaseLanguageForm.onLanguageChanged += new EventHandler<LanguageArgs>(BaseLanguageForm_onLanguageChanged);
}
/// <summary>
/// The function that was regidtered to the event
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The e.</param>
void BaseLanguageForm_onLanguageChanged(object sender, LanguageArgs e)
{
string lang = e.LanguageSymbol;
foreach (Control c in this.Controls)
{
ComponentResourceManager crm = new ComponentResourceManager(typeof(Form1));
crm.ApplyResources(c, c.Name, new CultureInfo(lang));
}
}
}
There are two kinds of things you must translate: The controls that are visible on the form and the strings you you need during runtime to say, change a button's Text or a MessageBox's caption etc..
You translate the controls you have on the form in the designer:
First do all the layout stuff in the Laguage = Standard.
Then change the Languge in the properties tab to another language.
Now translate all Texts in all controls.
You also may need to change the layout a little to allow for longer texts; this is fine!
Look at the project explorer: For each form and for each language there is now a new FormN.lang.resx file, e.g:
Form1.resx
Form1.en.resx
Form1.de.resx
Now when you call a changeLanguage function, maybe like this one:
private void ChangeLanguage(Control ctl, string lang)
{
resources.ApplyResources(ctl, ctl.Name, new CultureInfo(lang));
foreach (Control c in ctl.Controls) ChangeLanguage(c, lang);
}
maybe like this:
private void cb_language_Click(object sender, EventArgs e)
{
if (cb_language.Text == "DE")
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");
resources = new ComponentResourceManager(typeof(Form1));
ChangeLanguage(this, "de-DE");
cb_language.Text = "EN";
}
else
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
resources = new ComponentResourceManager(typeof(Form1));
ChangeLanguage(this, "en-US");
cb_language.Text = "DE";
}
}
..all visible controls will change their Texts.
The second thing to do is to create strings resource files, best one for standard and one for each language (repeating the standard values!): Add new element - resource file with names like these:
strings.resx
strings.de.resx
strings.en.resx
Then you add one name-value pair for each string you need in code, e.g:
msgCap_OW File Exists
msgTxt_OW Overwrite (Yes)
Use next free Index? (No)
Cancel?
cb_autoScrapeStart Start Timed Screenshots
Note: By shift-enter in a value field you can enter multiline values..
And finally you must change your code to use the strings resources, e.g. like this:
MessageBox.Show(strings.msgTxt_OW, strings.msgCap_OW, ..);
or:
cb_autoScrape.Text = (scrapeTimer.Enabled ?
strings.cb_autoScrapeStop : strings.cb_autoScrapeStart);

DataContext - ListView - Refresh UI - INotifyPropertyChanged

Working on an windows store app, I try to update/refresh a listView when some data is updated. But despite all samples and documentations I read, it doesn't work...
Here my code behind :
(I do not provide my xaml files, it's just a sample listView).
So the class which implements the INotifyPropertyChanged interface:
public class Download : INotifyPropertyChanged
{
public enum DownloadState
{
Running,
Waiting,
Pausing,
Paused,
Cancelling,
Cancelled
};
private String Uri;
private StorageFile storageFile;
private String tempFileName;
private String fileName;
private String version ;
private long totalSize ;
private long downloadedBytes;
private DownloadState state;
private Protocol protocol;
public Download(String Uri, StorageFile file, String fileName, String version, long totalSize, Protocol protocol)
{
this.Uri = Uri;
this.storageFile = file;
this.tempFileName = "";
this.fileName = fileName;
this.version = version;
this.totalSize = totalSize;
this.downloadedBytes = 0;
this.state = DownloadState.Waiting;
this.protocol = protocol;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
System.Diagnostics.Debug.WriteLine("Update!"); //ok
if (PropertyChanged != null)
{
//PropertyChanged is always null and shouldn't.
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public DownloadState State
{
get{return this.state;}
set {
this.state = value;
NotifyPropertyChanged();
}
}
//+some others methods
}
}
And the main page of the metro app :
// The Basic Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234237
namespace ClientAirNavLight_WS
{
/// <summary>
/// A basic page that provides characteristics common to most applications.
/// </summary>
public sealed partial class MainPage : ClientAirNavLight_WS.Common.LayoutAwarePage
{
/// <summary>
/// Represent a Web Service proxy.
/// </summary>
private AirNavLight_WSClientClient proxyWS;
/// <summary>
/// Initiialize the component of the application's main page.
/// </summary>
public MainPage()
{
this.InitializeComponent();
}
/// <summary>
/// Populates the page with content passed during navigation. Any saved state is also
/// provided when recreating a page from a prior session.
/// </summary>
/// <param name="navigationParameter">The parameter value passed to
/// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
/// </param>
/// <param name="pageState">A dictionary of state preserved by this page during an earlier
/// session. This will be null the first time a page is visited.</param>
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
}
/// <summary>
/// Preserves state associated with this page in case the application is suspended or the
/// page is discarded from the navigation cache. Values must conform to the serialization
/// requirements of <see cref="SuspensionManager.SessionState"/>.
/// </summary>
/// <param name="pageState">An empty dictionary to be populated with serializable state.</param>
protected override void SaveState(Dictionary<String, Object> pageState)
{
}
//Simulate data update.
private async void Button_Click(object sender, RoutedEventArgs e)
{
object selected = this.ListResult.SelectedItem;
if (selected != null)
{
//simulate an update in data.
// ListView should be refresh in order to reflect changes made here.
Download dl = (Download)selected;
if (dl.State == Download.DownloadState.Paused)
{
dl.State = Download.DownloadState.Running;
}
else
{
dl.State = Download.DownloadState.Paused;
}
}
else
{
//Just add an item to the list view.
StorageFile file = await this.getStorageFile("test");
Download dl = new Download("192.128.2.14", file, "test", "1.2", 100, Protocol.HTTP);
this.ListResult.Items.Add(dl);
this.ListResult.DataContext = dl;// Does not work.
}
}
private async Task<StorageFile> getStorageFile(String suggestedFileName)
{
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
// Dropdown of file types the user can save the file as
savePicker.FileTypeChoices.Add("Application/pdf", new List<string>() { ".pdf" });
savePicker.FileTypeChoices.Add("Archive", new List<string>() { ".zip", ".rar", ".7z" });
savePicker.FileTypeChoices.Add("Plain-text", new List<string>() { ".txt" });
// Default file name if the user does not type one in or select a file to replace
savePicker.SuggestedFileName = suggestedFileName;
return await savePicker.PickSaveFileAsync();
}
}
}
So How am I supposed to use listView.DataContext? Am I misunderstanding how use INotifyPropertyChanged?
EDIT :
How my listView is define :
<ListView x:Name="ListResult" HorizontalAlignment="Left" Height="200" Margin="10,56,0,0" VerticalAlignment="Top" Width="653" SelectionMode="Single"/>
Why are you setting this.ListResult.DataContext = dl? When dealing with ListViews, the ItemsSource is the collection for the all the objects that get iterated, not the DataContext. Furthermore, ItemsSource should be a collection and not one item. So if you're binding to a property, that property should exist as an item's property in the ItemsSource collection.
However, it looks like you don't have a collection so you're adding the dl directly to the ListView with this.ListResult.Items.Add(dl). That approach should work, however take out the this.ListResult.DataContext = dl or set this.ListResult.ItemsSource to a collection and add dl to that collection
I'm not familiar with [CallerMemberName] but if you're having problems with propertyName being null, try the following
public DownloadState State
{
get{return this.state;}
set {
if( this.state != value )
{
this.state = value;
NotifyPropertyChanged("State");
}
}
}
Furthermore, all properties that you want to bind to should be public and call NotifyPropertyChanged, like the following
private long totalSize ;
public long TotalSize
{
get{return this.totalSize;}
set {
if( this.totalSize != value )
{
this.totalSize = value;
NotifyPropertyChanged("TotalSize");
}
}
}
In your Download class, the only Property that will update in the UI is State, since it has a getter and setter.
Without your XAML it's not possible to see what you are trying to display, but normally, you would bind properties of your DataContext object (dl in this case) to different controls in a datatemplate that the listview could then display.
But these properties need to be public and have getters and setters for INotifyPropertyChanged to update the UI that these properties are bound to.
For instance, if you wanted the filename to show up in the ListView, you would need, as a minimum, to declare the filename property like this:
public String fileName {get; set; }
Zangdak -- One way around that problem is each time the items change in your collection just set set the ItemSource of the ListView to null and then set it back to your collection. If you do this the UI will update and you will see your new items added to your collection.
Paige Ake

Categories

Resources