UWP - Perform long view model creation and keep UI responsive - c#

I've build this example to show my issue.
I need to create a hierarchy to be shown in a treeview, treeview to be bound to the view model.
In the good old days of VB6 I would have used DoEvents to unlock the UI but here I'm not able to understand how to proceed.
On VS19 create a blank UWP project and call TestLoadSync it then copy paste this in the files:
App.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace TestLoadSync
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </su
/// mmary>
sealed partial class App : Application
{
public List<PropertyModel> _Properties;
public List<ImageModel> _ImagesHirerachy;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
_Properties = new List<PropertyModel>();
_ImagesHirerachy = new List<ImageModel>();
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
}
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
deferral.Complete();
}
}
}
MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace TestLoadSync
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private ObservableCollection<PropertyViewModel> _PropVM;
public MainPage()
{
DataLayer aDAL = new DataLayer();
_PropVM = new ObservableCollection<PropertyViewModel>();
this.InitializeComponent();
ProgB.Maximum = 1;
aDAL.loadData();
Debug.WriteLine(((App)App.Current)._Properties.Count());
Debug.WriteLine(((App)App.Current)._ImagesHirerachy.Count());
}
private void Button_Click(object sender, RoutedEventArgs e)
{
ProgB.Value = 0;
ProgB.Maximum = ((App)App.Current)._Properties.Count() + 1;
foreach (PropertyModel aProperty in ((App)App.Current)._Properties)
{
ProgB.Value++;
_PropVM.Add(new PropertyViewModel(aProperty));
}
ProgB.Value = ProgB.Maximum;
}
}
}
MainPage.xaml
<Page
x:Class="TestLoadSync.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:TestLoadSync"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Grid>
<Button
Width="296"
Height="143"
Margin="245,214,0,0"
VerticalAlignment="Top"
Click="Button_Click"
Content="Button" />
<ProgressBar
x:Name="ProgB"
Width="296"
Height="82"
Margin="245,82,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
</Grid>
</Page>
On the project add new... - Class - call it: DataLayer.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestLoadSync
{
public class PropertyModel
{
public int id;
public PropertyModel(int _id)
{
id = _id;
}
}
public class ImageModel
{
public int id;
public int property;
public int parent;
public string desc;
public ImageModel(int _id, int _property, int _parent, string _desc)
{
id = _id;
property = _property;
parent = _parent;
desc = _desc;
}
}
class PropertyViewModel
{
private PropertyModel _Property;
List<ImageViewModel> _Images;
public PropertyViewModel()
{
}
public PropertyViewModel(PropertyModel aProperty)
{
List<ImageModel> _SubImages;
_Property = aProperty;
Debug.WriteLine("Property: " + aProperty.id);
_Images = new List<ImageViewModel>();
_SubImages = ((App)App.Current)._ImagesHirerachy
.Where(x => x.property == aProperty.id && x.parent == 0)
.ToList();
foreach (ImageModel aImage in _SubImages)
{
_Images.Add(new ImageViewModel(aImage, 1));
}
}
}
class ImageViewModel
{
ImageModel _Image;
List<ImageViewModel> _Images;
public ImageViewModel()
{
}
public ImageViewModel(ImageModel aImage, int level)
{
List<ImageModel> _SubImages;
_Image = aImage;
string aS = new string('-', level);
Debug.WriteLine(" " + aS + aImage.id);
_Images = new List<ImageViewModel>();
_SubImages = ((App)App.Current)._ImagesHirerachy
.Where(x => x.parent == aImage.id && x.property == aImage.property)
.ToList();
foreach (ImageModel aSImage in _SubImages)
{
_Images.Add(new ImageViewModel(aSImage, ++level));
}
}
}
class DataLayer
{
private int maxProperties = 1000;
private int maxSubItems = 100;
public void loadData()
{
for (int i = 0; i < maxProperties; i++)
{
((App)App.Current)._Properties.Add(new PropertyModel(i));
}
for (int i = 0; i < maxSubItems; i++)
{
for (int j = 0; j < (i > maxSubItems / 2 ? maxSubItems / 2 : i); j++)
{
((App)App.Current)._ImagesHirerachy.Add(new ImageModel(maxProperties + i * (maxSubItems / 2) + j, i, 0, "-" + (((App)App.Current)._ImagesHirerachy.Count() + 1).ToString()));
}
}
for (int i = 0; i < maxSubItems; i++)
{
for (int j = 0; j < (i > maxSubItems / 4 ? maxSubItems / 4 : i); j++)
{
((App)App.Current)._ImagesHirerachy.Add(new ImageModel(maxProperties*2+ i * (maxSubItems/2) + j, i, maxProperties + i * (maxSubItems / 2) + j, "--" + (((App)App.Current)._ImagesHirerachy.Count() + 1).ToString()));
if (i == j)
{
((App)App.Current)._ImagesHirerachy.Add(new ImageModel(maxProperties * 4 + i * (maxSubItems / 2) + j, i, maxProperties*2 + i * (maxSubItems / 2) + j, "---" + (((App)App.Current)._ImagesHirerachy.Count() + 1).ToString()));
}
}
}
}
}
}
If you run it the ProgressBar will not fill in smoothly :( but it does not.
I've used simple numbers (1000/100) in the procedure to create the test structure but in my real case are much higher.
In the final app I'll use the MVVM light model and, obviously, the data will be read and saved from DB/File.
Note that the Models are both flat. The hierarchy is given thanks to the "parent" field in the image class that if is <>0 refers to the parent image. If is =0 then the image has to be attached to the property.
What I'm focusing here is how to create the ViewModel structures in the correct hierarchy so that I can bind the Page to the
_PropVM
and have the whole tree being built.

The ProgressBar can't response because your loop and the UI are executing on the same thread. While the loop is busy, it blocks the thread and can't update the UI. So you can calls the Task.Run( ) method to create a task and put time-consuming operations inside, then use await to perform asynchronous operations, like below:
private async void Button_Click(object sender, RoutedEventArgs e)
{
ProgB.Value = 0;
ProgB.Maximum = ((App)App.Current)._Properties.Count() + 1;
foreach (PropertyModel aProperty in ((App)App.Current)._Properties)
{
await Task.Run(() => _PropVM.Add(new PropertyViewModel(aProperty)));
ProgB.Value++;
}
ProgB.Value = ProgB.Maximum;
}

Related

C# WinUI 3 Get CS0053 error Inconsistent accessibility: property type 'INavigation' is less accessible than property 'App.Navigation'

Attempting to implement NavigationView navigation via code-behind using this solution I found:
https://xamlbrewer.wordpress.com/2021/07/06/navigating-in-a-winui-3-desktop-application/
I don't know what I am doing wrong. :-(.
I am new to C#, WinUI. Where is 'App.Navigation'?????
Outline of solution:
All navigation-related code is implemented in a partial class of the Shell window,
encapsulated in an interface that is
exposed via the App instance to
the different XAML pages.
I created an interface: (INavigation.cs)
using Microsoft.UI.Xaml.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MetricReporting.Interfaces
{
interface INavigation
{
NavigationViewItem GetCurrentNavigationViewItem();
List<NavigationViewItem> GetNavigationViewItems();
List<NavigationViewItem> GetNavigationViewItems(Type type);
List<NavigationViewItem> GetNavigationViewItems(Type type, string title);
void SetCurrentNavigationViewItem(NavigationViewItem item);
}
}
I created a partial class of my main window (MainWindow.xaml.Navigation.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MetricReporting
{
public partial class MainWindow : INavigation
{
public NavigationViewItem GetCurrentNavigationViewItem()
{
return NavigationView.SelectedItem as NavigationViewItem;
}
public List<NavigationViewItem> GetNavigationViewItems()
{
var result = new List<NavigationViewItem>();
var items = NavigationView.MenuItems.Select(i => (NavigationViewItem)i).ToList();
items.AddRange(NavigationView.FooterMenuItems.Select(i => (NavigationViewItem)i));
result.AddRange(items);
foreach (NavigationViewItem mainItem in items)
{
result.AddRange(mainItem.MenuItems.Select(i => (NavigationViewItem)i));
}
return result;
}
public List<NavigationViewItem> GetNavigationViewItems(Type type)
{
return GetNavigationViewItems().Where(i => i.Tag.ToString() == type.FullName).ToList();
}
public List<NavigationViewItem> GetNavigationViewItems(Type type, string title)
{
return GetNavigationViewItems(type).Where(ni => ni.Content.ToString() == title).ToList();
}
public void SetCurrentNavigationViewItem(NavigationViewItem item)
{
if (item == null)
{
return;
}
if (item.Tag == null)
{
return;
}
MasterContentFrame.Navigate(
Type.GetType(item.Tag.ToString()),
item.Content);
NavigationView.Header = item.Content;
NavigationView.SelectedItem = item;
}
}
}
I modified the App.xaml.cs:
using MetricReporting.Interfaces;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.UI.Xaml.Shapes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace MetricReporting
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : Application
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
///
// ** this is what I added per the web article **
public INavigation Navigation => (INavigation)m_window;
//public INavigation Navigation => m_window; Compiler does not like this
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
m_window = new MainWindow();
m_window.Activate();
}
private Window m_window;
}
}
Here is my MainWindow.xaml.cs in case it helps. The NavigationView code works well, I can navigate to all of the pages via navigation menu UI. :-). I just need to be able to navigate from the code behind. I am so sorry for the verbose post.
using MetricReporting.Pages;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System.Diagnostics;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace MetricReporting
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.Title = "EMB Metric Reporting Tool";
MasterContentFrame.Navigate(typeof(pageHome));
MasterNavigation.Header = "Home";
}
private void MasterNavigation_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
if (args.IsSettingsInvoked)
{
MasterContentFrame.Navigate(typeof(pageSettings));
}
else
{
// find NavigationViewItem with Content that equals InvokedItem
NavigationViewItem item = sender.MenuItems.OfType<NavigationViewItem>().First(x => (string)x.Content == (string)args.InvokedItem);
NavView_Navigate(item);
}
}
private void NavView_Navigate(NavigationViewItem item)
{
switch (item.Tag)
{
case "home":
MasterContentFrame.Navigate(typeof(pageHome));
MasterNavigation.Header = item.Content;
break;
case "datacollection":
MasterContentFrame.Navigate(typeof(pageDataCollection));
MasterNavigation.Header = item.Content;
break;
case "collectdata":
MasterContentFrame.Navigate(typeof(PageCollectMetricData));
MasterNavigation.Header = item.Content;
break;
case "goals":
MasterContentFrame.Navigate(typeof(pageGoals));
MasterNavigation.Header = item.Content;
break;
case "approvals":
MasterContentFrame.Navigate(typeof(pageComments));
MasterNavigation.Header = item.Content;
break;
case "reports":
MasterContentFrame.Navigate(typeof(pageReports));
MasterNavigation.Header = item.Content;
break;
case "admin":
MasterContentFrame.Navigate(typeof(pageAdmin));
MasterNavigation.Header = item.Content;
break;
case "metricstaging":
MasterContentFrame.Navigate(typeof(pageMetricStaging));
MasterNavigation.Header = item.Content;
break;
case "refmetricmain":
MasterContentFrame.Navigate(typeof(pageRefMetricMain));
MasterNavigation.Header = item.Content;
break;
}
}
private async void DisplayCommentDialog()
{
ContentDialog testDialog = new ContentDialog()
{
Title = "Main Window Loaded",
Content = "Main Window Loaded",
CloseButtonText = "Ok"
};
await testDialog.ShowAsync();
}
}
}
The error message tells you that INavigation must be public:
public interface INavigation
{
NavigationViewItem GetCurrentNavigationViewItem();
List<NavigationViewItem> GetNavigationViewItems();
List<NavigationViewItem> GetNavigationViewItems(Type type);
List<NavigationViewItem> GetNavigationViewItems(Type type, string title);
void SetCurrentNavigationViewItem(NavigationViewItem item);
}
If you define it as just interface INavigation { ... } (without the public keyword) it's internal by default and cannot be used as the return type of a public member.
So change interface INavigation to public interface INavigation in your code.

DllNotFoundException: hid.dll C# Linux

I am connecting a RFIDReader using USB and trying to communicate with it. It works well on windows. But this program should run on my raspberry pi whose operating system is raspbian and it tells me that a dll called hid.dll cannot be found when the program tried using the API of the RFIDReader. I guess its because the hid.dll is specific to windows. Since Linux doesn't have hid.dll, is there anything I can do to solve the problem to still get my program run on Linux? Is there anything similar to Hid.dll in linux?
My code dealing with the reader is as follows. When it executes the method InitReader() the problem will appear. Hope there's anyone can help me, thanks a lot!
using SkyeTek.Devices;
using SkyeTek.Tags;
using SkyeTek.STPv3;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Threading;
namespace RFIDReader
{
/// <summary>
/// this class represents the RFID reader, used to set the reader, send commond to the reader and ask response from the reader
/// </summary>
public class RFIDReader : EventArgs
{
public Device rfidReader { get; set; }
public String tagID;
public String buffer;
public static int count;
Thread timer; //the thread responsible for counting the timeout
public static bool tagRead = false; // determine if a person can pay for a product when a tag is detected
public event EventHandler<RFIDReader> TagDetected; //Tag detected event, raised once a tag is detected by the reader
/// <summary>
/// initiate the reader, set it as auto scanning tags
/// </summary>
public void InitReader()
{
if (FindLinkedDevices())
{
Console.WriteLine("RFIDReader: Opening device: " + rfidReader.ToString());
rfidReader.Open();
AutoScanTags();
rfidReader.Close();
}
}
/// <summary>
/// scanning tags automatically
/// </summary>
public void AutoScanTags()
{
STPv3Request request;
STPv3Response response;
SkyeTek.Tags.Tag tag = new SkyeTek.Tags.Tag();
tag.Type = TagType.AUTO_DETECT;
// Build the SelectTag request
request = new STPv3Request();
request.Command = STPv3Commands.SELECT_TAG;
request.Tag = tag;
//set the reader's flag as loop mode and inventory mode. So The reader reads all the tags in the field and then continuously
//scans for any tags that enter the field and reports back their tag IDs.
request.Loop = true;
request.Inventory = true;
// Issue the request to the output device
while (true)
{
request.Issue(rfidReader);
response = request.GetResponse();
if (response.ResponseCode == STPv3ResponseCode.SELECT_TAG_PASS)
{
//paymentValid = false;
buffer = BitConverter.ToString(response.TID);
if (buffer.Length > 0 && !buffer.Equals(tagID)) //if the tagID is a new ID, rasie tagdetected event, send data to RFIDData instance and start the timer
{
if (timer != null && timer.IsAlive)
{
timer.Abort();
}
tagID = buffer;
OnTagDetected(tagID);
timer = new Thread(Timing);
timer.Start();
}
else
{
if (buffer.Length > 0 && count >= 5) // if the tagID is not a new ID, check the timeout. If time is over, rasie tagdetected event, send data to RFIDData instance and start the timer
{
tagID = buffer;
OnTagDetected(tagID);
timer = new Thread(Timing);
timer.Start();
}
/*else
{
if(buffer.Length >0 && count >= 3 && request.GetResponse() != null)
{
paymentValid = true;
}
}*/
}
}
}
}
/// <summary>
/// Find the readers connected to the computer
/// </summary>
/// <returns></returns>
public bool FindLinkedDevices()
{
Console.WriteLine("RFIDReader: Enumerating linked devices");
Device[] LinkedDevices = USBDeviceFactory.Enumerate();
//Identify the RFID reader
if (LinkedDevices.Length == 0)
{
Console.WriteLine("RFIDReader: No USB devices found");
return false;
}
else
{
foreach (Device i in LinkedDevices)
{
Console.WriteLine("RFIDReader: USB devices found ---> " + i.ToString());
if (i.ToString().Equals("SkyeTek.Devices.USBDevice"))
{
rfidReader = i;
}
}
return true;
}
}
/// <summary>
/// Rasie an tagDetected event once the reader detects a tag
/// </summary>
/// <param name="TID"></param>
protected virtual void OnTagDetected(String TID)
{
if (TagDetected != null)
{
TagDetected(this, new RFIDReader() { tagID = TID });
}
}
/// <summary>
/// timing method running on the timer thread
/// </summary>
public void Timing()
{
for (count = 0; count < 5; count++)
{
System.Threading.Thread.Sleep(1000);
}
}
}
}

Popup about array rank size preventing me from saving

I have a specific user control with several properties, including one which is of another class. That class contains a public int[,] this[int x, int y] (I don't remember the exact term for that) as well as a public int[,] property and a private int[,] field. I then have a form containing that control. Whenever I attempt to edit the form and then save, it denies me from saving with the following popup appearing 3 to 6 times in a row:
Note that I don't need the information saved into these arrays in the designer; the value is set to a default each time anyways within the ExampleControl. I don't even have the ability to modify or see these arrays.
Here's all of the code needed to reproduce:
Create a new form application, and then delete the Form1.cs file generated.
Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace ArrayRankIssue
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ExampleForm());
}
}
}
ExampleClass.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ArrayRankIssue
{
public class ExampleClass
{
private int[,] data = new int[2, 2];
public int[,] Data {
get {
return data;
}
set {
if (value.GetLength(0) != data.GetLength(0) || value.GetLength(1) != data.GetLength(1)) {
throw new ArgumentException("Argument must match size of array exactly.");
}
data = value;
}
}
public int[,] this[int x, int y] {
get {
return data;
}
set {
if (value.GetLength(0) != data.GetLength(0) || value.GetLength(1) != data.GetLength(1)) {
throw new ArgumentException("Argument must match size of array exactly.");
}
data = value;
}
}
}
}
ExampleControl.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ArrayRankIssue
{
public partial class ExampleControl : UserControl
{
internal ExampleClass example = new ExampleClass();
public ExampleClass Example {
get {
return example;
}
set {
example = value;
}
}
public ExampleControl() {
InitializeComponent();
}
}
}
ExampleControl.Designer.cs:
namespace ArrayRankIssue
{
partial class ExampleControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
}
#endregion
}
}
ExampleForm.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ArrayRankIssue
{
public partial class ExampleForm : Form
{
public ExampleForm() {
InitializeComponent();
}
}
}
ExampleForm.Designer.cs:
namespace ArrayRankIssue
{
partial class ExampleForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
ArrayRankIssue.ExampleClass exampleClass8 = new ArrayRankIssue.ExampleClass();
this.exampleControl1 = new ArrayRankIssue.ExampleControl();
this.SuspendLayout();
//
// exampleControl1
//
this.exampleControl1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.exampleControl1.Example = exampleClass8;
this.exampleControl1.Location = new System.Drawing.Point(12, 12);
this.exampleControl1.Name = "exampleControl1";
this.exampleControl1.Size = new System.Drawing.Size(150, 150);
this.exampleControl1.TabIndex = 0;
//
// ExampleForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.exampleControl1);
this.Name = "ExampleForm";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private ExampleControl exampleControl1;
}
}
After creating all of these files, select Build-->Rebuild solution [note 1]. Then, double-click ExampleForm.cs, click on the outlined control, and then press left and then right on your keyboard [note 2]. Then, press Control and S, and you will be greeted with the same error message many times.
What I'm looking for is a way to keep this message from popping up (and hopefully to solve the reason why it is popping up, not just suppress it). I have found a simple workaround, which is to close the form designer window and then save, but that seems impractical. Once it is successfully saved, the form appears properly, so there also doesn't seem to be any other effects.
The one other mention of this error message was in this question, but that offered no useful solution.
Note 1: This option is only available in "Expert mode" - if you don't have it, go to Tools-->Settings-->Expert Settings)
Note 2: This is needed so that the file appears as modified by Visual Studio. If it isn't done, you can't force a second save.
Moving these lines worked for me:
From ExampleForm.Designer.cs:
ArrayRankIssue.ExampleClass exampleClass2 = new ArrayRankIssue.ExampleClass();
this.exampleControl1.Example = exampleClass2;
To ExampleForm.cs:
public partial class ExampleForm : Form
{
public ExampleForm()
{
InitializeComponent();
ArrayRankIssue.ExampleClass exampleClass2 = new ArrayRankIssue.ExampleClass();
this.exampleControl1.Example = exampleClass2;
}
}
Solution 2
If you're properties are already setup and you don't need to change them mark them with:
[ReadOnly(true)]
[Browsable(false)]
In your example add those attributes to Data and this in ExampleClass.cs.
You'll have to change your code, remove any existing controls from your form, compile then re-add

WPF Data Virtualization in MVVM pattern

,
i want to know how can i implement data virtualzation in mvvm pattern ?
i have searched but i didnt find data virtualzation using mvvm pattern.
this link descripes data virtualzation very good but not in mvvm.
http://www.codeproject.com/Articles/34405/WPF-Data-Virtualization
so please provide a link or example..
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Threading;
namespace DataVirtualization
{
/// <summary>
/// Interaction logic for DemoWindow.xaml
/// </summary>
public partial class DemoWindow
{
/// <summary>
/// Initializes a new instance of the <see cref="DemoWindow"/> class.
/// </summary>
public DemoWindow()
{
InitializeComponent();
// use a timer to periodically update the memory usage
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 1);
timer.Tick += timer_Tick;
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
tbMemory.Text = string.Format("{0:0.00} MB", GC.GetTotalMemory(true)/1024.0/1024.0);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// create the demo items provider according to specified parameters
int numItems = int.Parse(tbNumItems.Text);
int fetchDelay = int.Parse(tbFetchDelay.Text);
DemoCustomerProvider customerProvider = new DemoCustomerProvider(numItems, fetchDelay);
// create the collection according to specified parameters
int pageSize = int.Parse(tbPageSize.Text);
int pageTimeout = int.Parse(tbPageTimeout.Text);
if ( rbNormal.IsChecked.Value )
{
DataContext = new List<Customer>(customerProvider.FetchRange(0, customerProvider.FetchCount()));
}
else if ( rbVirtualizing.IsChecked.Value )
{
DataContext = new VirtualizingCollection<Customer>(customerProvider, pageSize);
}
else if ( rbAsync.IsChecked.Value )
{
DataContext = new AsyncVirtualizingCollection<Customer>(customerProvider, pageSize, pageTimeout*1000);
}
}
}
}
Thanks

Multithreading 4-Tier Mixed Producer Consumer Pattern - Threads Not Alternating Properly

Here is the problem I am trying to model: I have an incoming call center (no outbound calls). There are 3 employee levels - Freshers, Technical Lead, Project Manager. In our call center there is only one TL, one PM and multiple Freshers. Calls that the Freshers cannot handle are escalated to the TL, and calls that the TL cannot handle are escalated to the PM.
I need to take an OO C# approach.
Here is my current attempt: I used C# ConcurrentQueue since I thought it would take care of the 'locks'. I want FIFO for call center. I made a queue for each level.
I have a producer (callers) adding calls to the first queue. Mixed prod/consumer freshers check the call (take or escalate to the next queue). Mixed prod/consumer tl, then a pure consumer project manager.
The output is not what I expect. Only the first fresher runs and the project manager does not run at all. I expect a lot more alternation as the calls are added to the queue.
My code is below. Does anyone have a better approach to this problem or is there something wrong with my code?
The CallCenter Class is where most of the action takes place.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
///
/// MIXED CONSUMER/PRODUCER TYPE
/// </summary>
class Fresher
{
// add a class variable for the number of Employee objects instantiated
private static int fresherNum = 0;
private int fresherId;
private ConcurrentQueue<Call> incommingCalls;
private ConcurrentQueue<Call> outgoingCalls;
public Fresher(ConcurrentQueue<Call> calls, ConcurrentQueue<Call> outcalls)
{
fresherId = ++fresherNum;
incommingCalls = calls;
outgoingCalls = outcalls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(HandleCalls));
thread.Start();
}
public int ID
{
get { return fresherId; }
}
/// <summary>
///
/// </summary>
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
Call call;
incommingCalls.TryDequeue(out call);
if (call != null)
{
if (call.EscalationLevel == 0)
{
TakeCalls(call);
}
else
{
TransferCalls(call);
}
}
}
}
/// <summary>
/// Transfer to the TL
/// </summary>
public void TransferCalls(Call call)
{
outgoingCalls.Enqueue(call);
Console.WriteLine(".......Fresher {0} escalated call {1}", ID, call.CallID);
}
/// <summary>
/// Consume the calls
/// </summary>
public void TakeCalls(Call call)
{
Console.WriteLine("Fresher {0} handled call {1}", ID, call.CallID);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
/// MIXED CONSUMER/PRODUCER TYPE
/// </summary>
class TechnicalLead
{
// add a class variable for the number of Employee objects instantiated
private static int tlNum = 0;
private int tlId;
private ConcurrentQueue<Call> incommingCalls;
private ConcurrentQueue<Call> outgoingCalls;
public TechnicalLead(ConcurrentQueue<Call> calls, ConcurrentQueue<Call> outcalls)
{
tlId = ++tlNum;
incommingCalls = calls;
outgoingCalls = outcalls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(HandleCalls));
thread.Start();
}
public int ID
{
get { return tlId; }
}
/// <summary>
///
/// </summary>
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
Call call;
incommingCalls.TryDequeue(out call);
if (call != null)
{
if (call.EscalationLevel == 1)
{
TakeCalls(call);
}
else
{
TransferCalls(call);
}
}
}
}
/// <summary>
/// Transfer to the PM
/// </summary>
public void TransferCalls(Call call)
{
//Console.WriteLine(".......Technical Lead {0} escalated call {1}", ID, call.CallID);
outgoingCalls.Enqueue(call);
}
/// <summary>
/// Consume the calls
/// </summary>
public void TakeCalls(Call call)
{
Console.WriteLine("Technical Lead {0} handled call {1}", ID, call.CallID);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CallCenterThreaded
{
class Call
{
private static int numberCalls = 0;
private int callno;
private int esclataion;
public Call()
{
callno = ++numberCalls;
esclataion = 0;
if(callno % 3 == 0)
{
esclataion = 1;
}
if(callno % 5 == 0)
{
esclataion = 2;
}
}
public int CallID { get { return callno; } }
public int EscalationLevel { get { return esclataion; } }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
///
/// </summary>
class CallCenter
{
private ConcurrentQueue<Call> fresherCalls;
private ConcurrentQueue<Call> tlCalls;
private ConcurrentQueue<Call> pmCalls;
private List<Caller> myCallers;
private List<Fresher> myFreshers;
private TechnicalLead tl;
private ProjectManager pm;
public CallCenter()
{
//initial incomming calls to the fresher queue
fresherCalls = new ConcurrentQueue<Call>();
tlCalls = new ConcurrentQueue<Call>();
pmCalls = new ConcurrentQueue<Call>();
myFreshers = new List<Fresher>();
myCallers = new List<Caller>();
generate_callers();
generate_freshers();
tl = new TechnicalLead(tlCalls, pmCalls);
pm = new ProjectManager(pmCalls);
}
/// <summary>
///
/// </summary>
private void generate_freshers()
{
for (int i = 0; i < 5; i++ )
{
myFreshers.Add(new Fresher(fresherCalls, tlCalls));
}
}
/// <summary>
///
/// </summary>
private void generate_callers()
{
for (int i = 0; i < 5; i++ )
{
myCallers.Add(new Caller(fresherCalls));
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
/// PURE CONSUMER
/// </summary>
class ProjectManager
{
// add a class variable for the number of Employee objects instantiated
private static int pmNum = 0;
private int pmId;
private ConcurrentQueue<Call> incommingCalls;
public ProjectManager(ConcurrentQueue<Call> calls)
{
pmId = ++pmNum;
incommingCalls = calls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(HandleCalls));
thread.Start();
}
public int ID
{
get { return pmId; }
}
/// <summary>
///
/// </summary>
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
Call call;
incommingCalls.TryDequeue(out call);
if (call != null && call.EscalationLevel == 2)
{
TakeCalls(call);
}
}
}
/// <summary>
/// Consume the calls
/// </summary>
public void TakeCalls(Call call)
{
Console.WriteLine("Project Manager {0} handled call {1}", ID, call.CallID);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
class MainClass
{
static void Main(string[] args)
{
CallCenter myCenter = new CallCenter();
Console.ReadLine();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Threading;
namespace CallCenterThreaded
{
/// <summary>
/// This is a producer. It produces calls and adds them to the queue.
/// PURE PRODUCER TYPE
/// </summary>
class Caller
{
private ConcurrentQueue<Call> incommingCalls;
public Caller(ConcurrentQueue<Call> calls)
{
incommingCalls = calls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(placeCalls));
thread.Start();
}
public void placeCalls()
{
//place 10 calls
for (int callno = 0; callno < 4; callno++)
{
//Console.WriteLine("Call {0} was added to the queue", callno);
incommingCalls.Enqueue(new Call());
}
}
}
}
The problem is in the HandleCalls() methods:
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
…
}
}
What this code does is to check incomingCalls and if there are none, it immediately exits the thread. It's as if the worker came to work, looked at his queue of calls, found nothing there (because he came to work at the same time as the freshers who are supposed to redirect the calls) and so he left and went home.
What you need to do is to wait if there is no work at the moment. Probably the best way to do that is to use BlockingCollection instead of ConcurrentQueue.
Also, your design doesn't seem to that good. For example, there is lots of repeated code.

Categories