Custom Accepted Operation in Drag and Drop - c#

I am making a library management software. This is the screenshot:
I have implementing functionalities like dragging a book into the delete icon to delete the book. But there are two obstacles:
DataPackageOperation has only four possibilities: Copy, link, move none. So, after four, it is difficult to differentiate which AppBarButton is the book dropped on.
I plan to add more items to the CommandBar. But there are only four possible operations
I need a way to give the user a custom feedback as to which AppBarButton is the book currently dragged over. DataPackageOperation contains only four. Out of which, 'None' cannot be used(because it will be confusing). Is there a way to provide that feedback?

I need a way to give the user a custom feedback as to which AppBarButton is the book currently dragged over
You could give the user a custom feedback via custom Drag UI. The follow code comes from XamlDragAndDrop official code sample.
private void TargetTextBox_DragEnter(object sender, Windows.UI.Xaml.DragEventArgs e)
{
/// Change the background of the target
VisualStateManager.GoToState(this, "Inside", true);
bool hasText = e.DataView.Contains(StandardDataFormats.Text);
e.AcceptedOperation = hasText ? DataPackageOperation.Copy : DataPackageOperation.None;
if (hasText)
{
e.DragUIOverride.Caption = "Drop here to insert text";
// Now customize the content
if ((bool)HideRB.IsChecked)
{
e.DragUIOverride.IsGlyphVisible = false;
e.DragUIOverride.IsContentVisible = false;
}
else if ((bool)CustomRB.IsChecked)
{
var bitmap = new BitmapImage(new Uri("ms-appx:///Assets/dropcursor.png", UriKind.RelativeOrAbsolute));
// Anchor will define how to position the image relative to the pointer
Point anchor = new Point(0,52); // lower left corner of the image
e.DragUIOverride.SetContentFromBitmapImage(bitmap, anchor);
e.DragUIOverride.IsGlyphVisible = false;
e.DragUIOverride.IsCaptionVisible = false;
}
// else keep the DragUI Content set by the source
}
}

Related

How to check if a picture box contains a certain image using an IF statement

I am trying to check if a PictureBox contains a certain image, the way I am trying to do it seems like it would work in my head, however, does not, i am not sure if there is any other way to check if the picturebox on the form contains a certain image.
private void user_btn_Click(object sender, EventArgs e)
{
//If statement to check if the forms picture box contains a certain image
if (pictureBox1.Image == Resources.user_male_white_red_brown)
{
this.Hide();
UserProfile User = new UserProfile();
User.ShowDialog();
User.pictureBox1.Image = Resources.user_male_white_red_brown;
this.Close();
}
else if (pictureBox1.Image == Resources.user_female_olive_orange)
{
this.Hide();
UserProfile User = new UserProfile();
User.ShowDialog();
User.pictureBox1.Image = Resources.user_female_olive_orange;
this.Close();
}
}
Although PictureBox Image might be identical as the one in the resources but they are not the same as reference. (Imagine like you have 2 copy of the same photo although their image is the same but they are 2 separate photos).
There are a few ways you can do it, one of them (a simple one) is to set the picturebox Tag to a relevent value whenever setting its image and compare that value instead of comparing images:
User.pictureBox1.Image = Resources.user_male_white_red_brown;
User.pictureBox1.Tag = "user_male_white_red_brown";
And then:
if((string)User.pictureBox1.Tag == "user_male_white_red_brown")
{
// your logic
}
This way you need to set PictureBox tag whenever you set its image.
Another way would be loading all images from resources to an array and setting the PictureBox image from the array, this way as the reference of both images (picturebox.Image and the image item in the array) are the same comparison would work for images but I think the first solution is easier.

Returning more than one variable in a C# 'get' statement

In my Excel Add-In, I have created two task panes - with each ones visibility being from two different values, requiring both to be in a return statement, however it will only allow me to return one of the values. These are 'taskPaneValue' and 'taskPaneValue2'.
How do I go about having both returned in the 'get' statement.
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
taskPaneControl2 = new FileChooser();
taskPaneValue2 = this.CustomTaskPanes.Add(taskPaneControl2, "File Chooser");
taskPaneValue2.VisibleChanged += new EventHandler(taskPaneValue_VisibleChanged);
taskPaneValue2.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionFloating;
taskPaneValue2.Height = 600;
taskPaneValue2.Width = 600;
taskPaneValue2.DockPositionRestrict = Office.MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoChange;
//These three lines of code start by initiating the TaskPane control (namely aLaCarteMenu())
//It then goes on to set the name of the menu "A La Carte Menu" which appears on the top left of the window before stating its visibility.
taskPaneControl1 = new aLaCarteMenu();
taskPaneValue = this.CustomTaskPanes.Add(taskPaneControl1, "A La Carte Menu");
taskPaneValue.VisibleChanged +=
//The following four lines of code are used to display the visiblity of the AddIn.
//The docking position is set to float, with a resolution of 980x1920. This is designed for a 1080p screen, however still working on changing it to fit screens dynamically.
new EventHandler(taskPaneValue_VisibleChanged);
taskPaneValue.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionFloating;
taskPaneValue.Height = 980;
taskPaneValue.Width = 1920;
//This line of code sets the position to be restricted to what has been set above (floating). This allows for the pane to be moved around the screen, as well as to be resized.
//This stops the pane from locking on to the right, left, top or bottom sections of the Excel Window.
taskPaneValue.DockPositionRestrict = Office.MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoChange;
}
private void taskPaneValue_VisibleChanged(object sender, System.EventArgs e)
{
Globals.Ribbons.ManageTaskPaneRibbon.toggleButton1.Checked = taskPaneValue.Visible;
Globals.Ribbons.ManageTaskPaneRibbon.toggleButton2.Checked = taskPaneValue2.Visible;
}
public Microsoft.Office.Tools.CustomTaskPane TaskPane
{
get
{
return taskPaneValue2;
}
}
The final 'get' statement is the one I wish to return both variables.
Use a Tuple or create a class that has all the properties you are looking for and make that the return type of the function.
You can also create a method with out parameter modifier, if it'still possible to you. Please, check the following link: https://msdn.microsoft.com/en-us/library/ee332485.aspx

Screenshots of multiple actionbar tabs

I am using Xamarin and C# but I suspect the problem is equally valid in a Java environment.
I have an ActionBar Activity that hosts three tabs each of which hosts a fragment. It uses a ViewPager to allow the user to swipe between the tabs.
The requirement is to programmatically screenshot each tab and then email these as attachments.
The problem is that whilst the ActionBar/ViewPager works well it also optimises the tabs - effectively it isn't creating a fragment's view until it is next in line to be shown. So, if you're on tab 0 - the first tab - then the fragment view for tab 2 is null. So it can't be screenshot.
To overcome this I have tried to set any tab/fragment that has a null view to be selected. This generates the view but because setting it to be selected does not actually render it on screen the view does not have a width or a height value so again it cannot be screenshot (this is the reason for the defensive check at the start of the code taking the screenshot).
So, I guess my question is how can I force the tab to be rendered on screen so that it is correctly filled out and can be screenshot?
My main code extracts are as follows:
private void EmailReport()
{
List <Bitmap> bitmaps = new List<Bitmap>();
List <string> summaryFiles = new List<string>();
// remember the tab we're on
var selectedTab = this.ActionBar.SelectedNavigationIndex;
// take the screenshots
for (int fragmentNumber = 0; fragmentNumber < projectFragmentPagerAdapter.Count; fragmentNumber++)
{
Android.Support.V4.App.Fragment fragment = projectFragmentPagerAdapter.GetItem(fragmentNumber);
if (fragment.View == null)
{
this.ActionBar.GetTabAt(fragmentNumber).Select();
fragment = projectFragmentPagerAdapter.GetItem(fragmentNumber);
}
bitmaps.Add(ScreenShot(fragment.View));
}
// set the active tab back
this.ActionBar.GetTabAt(selectedTab).Select();
//write the screenshots into file
int i = 0;
foreach(Bitmap bitmap in bitmaps)
{
if (bitmap != null)
summaryFiles.Add(BitmapToFile(bitmap, this.ActionBar.GetTabAt(i).Text));
i++;
}
// now send the file
EmailSupport.SendAttachments(this, summaryFiles);
}
private Bitmap ScreenShot(View fragmentRootView)
{
if (fragmentRootView == null || fragmentRootView.Width == 0 || fragmentRootView.Height == 0)
return null;
fragmentRootView.DrawingCacheEnabled = true;
//create a bitmap for the layout and then draw the view into it
Bitmap bitmap = Bitmap.CreateBitmap(fragmentRootView.Width, fragmentRootView.Height,Bitmap.Config.Argb8888);
Canvas canvas = new Canvas(bitmap);
//Get the view's background
Drawable bgDrawable = fragmentRootView.Background;
if (bgDrawable!=null) // has background drawable, then draw it on the canvas
bgDrawable.Draw(canvas);
else // does not have background drawable, then draw white background on the canvas
canvas.DrawColor(Color.White);
// draw the view on the canvas
fragmentRootView.Draw(canvas);
fragmentRootView.DrawingCacheEnabled = false;
return bitmap;
}
Any help would be gratefully received.
The solution in the end was very simple. The ViewPager has a setting controlling the number of pages (fragments) that it will hold "activated". This defaults to 1. As I had 3 tabs this meant there was always one tab (fragment) out of reach.
So, whilst setting up the ViewPager do the following before the tabs are added:
reportViewPager.OffscreenPageLimit = pageCount - 1;
Or in Java
reportViewPager.setOffscreenPageLimit(pageCount - 1);
I hope this helps someone else avoid wasting hours.

FastColoredTextbox AutoWordSelection?

FastColoredTextbox is an user-control that can be downloaded in this url, it looks like this:
Its an amazing control but only can select one word when doubleclicking on the text, can't hold the mouse to select more words, so it only selects the entire current word over the mouse pointer even if you try to move the mouse cursor to left or right to select more text.
I have not found any information explaining the problem, and all of the official example projects has this problem.
Nobody means how to make an AutoWordSelection equivalent of a default TextBox for a FastcoloredTextbox control, but even the most important thing is:
How to select just more than one word with the mouse?
UPDATE:
#mostruash answer is very instructive but in all this time I could not carry out the modifications by myself.
I need a huge help from a C# programmer to carry out this task, my knowledge of C# is very low and the modifications that I made to the source did not work (don't compiled), I went back to the original user-control source to not end up spoiling more. I hate to say this but this time I need the job done, this source is too much for me.
If I'm requesting for too much then maybe with the necesary extended instructions of a C# developer, explaining how to accomplish this step by step, maybe I could carry it out by myself.
UPDATE
A video that demostrates the problem:
https://www.youtube.com/watch?v=Cs2Sh2tMvII
UPDATE
Another demo, I show what the FastColoredTextBox can't do but I would like to do like every other text-editor can do:
I've checked the source code of the project. Dragging is cancelled if a double click occurs and SelectWord is called.
You could modify the source code to include the feature that you request. (https://github.com/PavelTorgashov/FastColoredTextBox). In that case:
You must trace selections that start with double clicks.
Instead of calling SelectWord function, use the Selection class and draggedRange attribute to mark the selected word in OnMouseMove.
You also must handle deselection of words in OnMouseMove.
You must also select spaces between words in OnMouseMove.
The double click is handled in the code piece below:
if (!isLineSelect)
{
var p = PointToPlace(e.Location);
if (e.Clicks == 2)
{
mouseIsDrag = false; //Here, drag is cancelled.
mouseIsDragDrop = false;
draggedRange = null; //Drag range is nullified
SelectWord(p); //SelectWord is called to mark the word
return;
}
if (Selection.IsEmpty || !Selection.Contains(p) || this[p.iLine].Count <= p.iChar || ReadOnly)
OnMouseClickText(e);
else
{
mouseIsDragDrop = true;
mouseIsDrag = false;
}
}
EDIT:
This may require a lot of work to accomplish. So maybe you should use another tool/library. I have not studied the whole source code so there will probably be additional steps to those provided above.
For example, to trace double clicks you can do the following:
Define a class variable/property in FastColoredTextbox.cs: bool isDoubleClick.
Set it to true in OnMouseDown under if(e.Clicks == 2) condition. Set it to false in all other conditions.
Set it to false in OnMouseClick or OnMouseUp or in other relevant mouse event handlers.
That way you will know if series of mouse events had started with a double click event or not. Then you would act accordingly in OnMouseMove because that is where you (un)mark characters or (un)mark words.
LAST WORDS OF CAUTION:
The author of that project did not include any inline comments or any other means of documentation so you will be studying the code line by line to understand what each function/part does.
Add the following statement between Line 5276 and line 5277 in the class FastColoredTextBox.cs:
SelectWord(p);
mouseIsDrag = true; // here
return;
Note that implementing the ultimate behavior would require a good bunch of coding. Whereas the workaround mentioned above might satisfy your needs.
As #mostruash points out in his answer, that is the place where author cancels the mouse drag. Not sure why he deliberately prevents this feature. Only he knows.
if (e.Clicks == 2)//Line 5270
{
mouseIsDrag = false;
mouseIsDragDrop = false;
draggedRange = null;
SelectWord(p);
return;
}
I didn't read whole code, and I have no reason to do it. I just checked quickly and removed them. And it works as you expect.
if (e.Clicks == 2)//Line 5270
{
//Comment or remove completely.
//mouseIsDrag = false;
//mouseIsDragDrop = false;
//draggedRange = null;
SelectWord(p);
return;
}
Note: Am not sure this breaks something else, I've not tested. At least that works. Test it yourself.
My solution is a bit tweaky, but seems to work at first glance.
You have to make some changes in the Code:
Add mouseIsWholeWordSelection flag and a Range variable which can store the initial selected range after double click (best after line 100, I guess):
private bool mouseIsWholeWordSelection;
private Range mouseIsWholeWordSelectionBaseRange;
Change the selection code for double click event as stated above and extend it a bit (line 5222):
if (e.Clicks == 2)
{
//mouseIsDrag = false;
mouseIsDragDrop = false;
mouseIsWholeWordSelection = true;
//draggedRange = null;
SelectWord(p);
mouseIsWholeWordSelectionBaseRange = Selection.Clone();
return;
}
Add evaluation of dragging event for recreating selection (line 5566):
else if (place != Selection.Start)
{
if (mouseIsWholeWordSelection)
{
Selection.BeginUpdate();
var oldSelection = Selection.Clone();
SelectWord(place);
if (Selection.End >= mouseIsWholeWordSelectionBaseRange.End)
{
Selection.Start = (mouseIsWholeWordSelectionBaseRange.Start > Selection.Start) ? mouseIsWholeWordSelectionBaseRange.Start : Selection.Start;
Selection.End = mouseIsWholeWordSelectionBaseRange.End;
}
else if (Selection.Start < mouseIsWholeWordSelectionBaseRange.End)
{
Selection.Start = new Place(Selection.End.iChar, Selection.End.iLine);
Selection.End = mouseIsWholeWordSelectionBaseRange.Start;
}
Selection.EndUpdate();
DoCaretVisible();
Invalidate();
}
else
{
Place oldEnd = Selection.End;
Selection.BeginUpdate();
if (Selection.ColumnSelectionMode)
{
Selection.Start = place;
Selection.ColumnSelectionMode = true;
}
else
Selection.Start = place;
Selection.End = oldEnd;
Selection.EndUpdate();
DoCaretVisible();
Invalidate();
}
return;
}
Add at every place where isMouseDrag is being set to false:
isMouseWholeWordSelection = false;
And there you go.

Using image transparency between Picture Boxes stores as Arrays

I am using c# and winForms to create an application that allows me to have 6 Picture Boxes (each with a different image) on top of one another. Each image has alot of white space so i am trying to use transparency to allow the user to toggle images on and off. When an image is toggled off, the parent/child of all the other images will be updated to allow the transparency to work.
I First created a custom class:
public class MyImageWrapper
{
public MyImageWrapper Parent { get; set; }
public PictureBox PictureBox { get; set; }
public MyImageWrapper(PictureBox i, MyImageWrapper parent = null)
{
Parent = parent;
PictureBox = i;
}
}
Then I Created the Array:
MyImageWrapper[] pictureBoxArray = new MyImageWrapper[6];
This next code is a test to Check if transparency works:
pictureBox[0] = new MyImageWrapper(pictureBox1);
pictureBox[1] = new MyImageWrapper(pictureBox2);
pictureBox1.Image = (Image.FromFile(""+ Application.StartupPath +"../../../images/imageA.png"));
pictureBox2.Image = (Image.FromFile(""+ Application.StartupPath +"../../../images/imageB.png"));
pictureBoxArray[1].Parent = pictureBoxArray[0];
Unfortunately I do not receive any error messages so it seems to be working. However when I run the program Picture Box 2 is not a child of picture box 1 (and thus transparency does not work)
I have not gotten as far as setting the images to be turned on or off yet, I am still trying to sort out the transparency.
The problem specifically is this line:
pictureBoxArray[1].Parent = pictureBoxArray[0];
When testing I replaced the above line with:
pictureBox2.Parent = pictureBox1;
This does exactly the same thing (but works!). However the way my program needs to work later I cannot do it like this. I need to fix the Array version.
Any help would be greatly appreciated.
Wouldn't you need to put:
pictureBoxArray[1].PictureBox.Parent = pictureBoxArray[0].PictureBox
?
The two lines:
pictureBoxArray[1].Parent = pictureBoxArray[0];
pictureBox2.Parent = pictureBox1;
You have put are not equivalent. In one you are assigning the parent of the ImageWrapper and in the other you are assigning the parent of the PictureBox.
I don't know if this is an error in how you have presented the code or in your program itself.

Categories

Resources